Refactor to Dyntopo node customdata commit.
Don't use a dedicated node layer but use temporary int layer instead. Works like a charm as long as we are careful resetting the layer when needed (after pbvh clearing and always after bmesh has been filled in undo) Tip by Campbell, thanks!
This commit is contained in:
@@ -135,6 +135,8 @@ typedef struct SculptSession {
|
||||
|
||||
/* BMesh for dynamic topology sculpting */
|
||||
struct BMesh *bm;
|
||||
int cd_vert_node_offset;
|
||||
int cd_face_node_offset;
|
||||
bool bm_smooth_shading;
|
||||
/* Undo/redo log for dynamic topology sculpting */
|
||||
struct BMLog *bm_log;
|
||||
|
||||
@@ -67,7 +67,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
|
||||
struct DMGridAdjacency *gridadj, int totgrid,
|
||||
struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats,
|
||||
unsigned int **grid_hidden);
|
||||
void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log);
|
||||
void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset);
|
||||
|
||||
void BKE_pbvh_free(PBVH *bvh);
|
||||
void BKE_pbvh_free_layer_disp(PBVH *bvh);
|
||||
|
||||
@@ -269,7 +269,8 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
|
||||
|
||||
BKE_pbvh_build_bmesh(cddm->pbvh, ob->sculpt->bm,
|
||||
ob->sculpt->bm_smooth_shading,
|
||||
ob->sculpt->bm_log);
|
||||
ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset,
|
||||
ob->sculpt->cd_face_node_offset);
|
||||
|
||||
pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color);
|
||||
}
|
||||
|
||||
@@ -1037,17 +1037,6 @@ static void layerDefault_mvert_skin(void *data, int count)
|
||||
}
|
||||
}
|
||||
|
||||
static void layerDefault_dyntopo_node(void *data, int count)
|
||||
{
|
||||
int *indices = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
indices[i] = DYNTOPO_NODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void layerInterp_mvert_skin(void **sources, const float *weights,
|
||||
const float *UNUSED(sub_weights),
|
||||
int count, void *dest)
|
||||
@@ -1196,8 +1185,6 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
{sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
/* 40: CD_TESSLOOPNORMAL */
|
||||
{sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL},
|
||||
/* 41: CD_DYNTOPO_NODE */
|
||||
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_dyntopo_node},
|
||||
};
|
||||
|
||||
/* note, numbers are from trunk and need updating for bmesh */
|
||||
@@ -1214,7 +1201,6 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
|
||||
/* 30-34 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDPreviewLoopCol", "CDBMElemPyPtr", "CDPaintMask",
|
||||
/* 35-36 */ "CDGridPaintMask", "CDMVertSkin",
|
||||
/* 37-40 */ "CDFreestyleEdge", "CDFreestyleFace", "CDMLoopTangent", "CDTessLoopNormal",
|
||||
/* 41 */ "CDDyntopoNode"
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -96,8 +96,7 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver
|
||||
}
|
||||
|
||||
/* Recursively split the node if it exceeds the leaf_limit */
|
||||
static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index,
|
||||
const int cd_vert_node_offset, const int cd_face_node_offset)
|
||||
static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
|
||||
{
|
||||
GSet *empty, *other;
|
||||
GSetIterator gs_iter;
|
||||
@@ -105,7 +104,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index,
|
||||
BB cb;
|
||||
float mid;
|
||||
int axis, children;
|
||||
|
||||
const int cd_vert_node_offset = bvh->cd_vert_node_offset;
|
||||
const int cd_face_node_offset = bvh->cd_face_node_offset;
|
||||
n = &bvh->nodes[node_index];
|
||||
|
||||
if (BLI_gset_size(n->bm_faces) <= bvh->leaf_limit) {
|
||||
@@ -210,8 +210,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index,
|
||||
|
||||
/* Recurse */
|
||||
c1 = c2 = NULL;
|
||||
pbvh_bmesh_node_split(bvh, prim_bbc, children, cd_vert_node_offset, cd_face_node_offset);
|
||||
pbvh_bmesh_node_split(bvh, prim_bbc, children + 1, cd_vert_node_offset, cd_face_node_offset);
|
||||
pbvh_bmesh_node_split(bvh, prim_bbc, children);
|
||||
pbvh_bmesh_node_split(bvh, prim_bbc, children + 1);
|
||||
|
||||
/* Array maybe reallocated, update current node pointer */
|
||||
n = &bvh->nodes[node_index];
|
||||
@@ -224,7 +224,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index,
|
||||
}
|
||||
|
||||
/* Recursively split the node if it exceeds the leaf_limit */
|
||||
static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index, const int cd_vert_node_offset, const int cd_face_node_offset)
|
||||
static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
|
||||
{
|
||||
GHash *prim_bbc;
|
||||
GSet *bm_faces;
|
||||
@@ -260,7 +260,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index, const int cd
|
||||
BLI_ghash_insert(prim_bbc, f, bbc);
|
||||
}
|
||||
|
||||
pbvh_bmesh_node_split(bvh, prim_bbc, node_index, cd_vert_node_offset, cd_face_node_offset);
|
||||
pbvh_bmesh_node_split(bvh, prim_bbc, node_index);
|
||||
|
||||
BLI_ghash_free(prim_bbc, NULL, NULL);
|
||||
MEM_freeN(bbc_array);
|
||||
@@ -1144,16 +1144,16 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
|
||||
/***************************** Public API *****************************/
|
||||
|
||||
/* Build a PBVH from a BMesh */
|
||||
void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log)
|
||||
void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
|
||||
const int cd_vert_node_offset, const int cd_face_node_offset)
|
||||
{
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
PBVHNode *n;
|
||||
int node_index = 0;
|
||||
|
||||
const int cd_vert_node_offset = CustomData_get_offset(&bm->vdata, CD_DYNTOPO_NODE);
|
||||
const int cd_face_node_offset = CustomData_get_offset(&bm->pdata, CD_DYNTOPO_NODE);
|
||||
|
||||
bvh->cd_vert_node_offset = cd_vert_node_offset;
|
||||
bvh->cd_face_node_offset = cd_face_node_offset;
|
||||
bvh->bm = bm;
|
||||
|
||||
BKE_pbvh_bmesh_detail_size_set(bvh, 0.75);
|
||||
@@ -1178,7 +1178,7 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log)
|
||||
|
||||
/* Recursively split the node until it is under the limit; if no
|
||||
* splitting occurs then finalize the existing leaf node */
|
||||
if (!pbvh_bmesh_node_limit_ensure(bvh, node_index, cd_vert_node_offset, cd_face_node_offset))
|
||||
if (!pbvh_bmesh_node_limit_ensure(bvh, node_index))
|
||||
pbvh_bmesh_node_finalize(bvh, 0, cd_vert_node_offset, cd_face_node_offset);
|
||||
}
|
||||
|
||||
@@ -1190,8 +1190,8 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
|
||||
BLI_buffer_declare_static(BMFace *, edge_loops, BLI_BUFFER_NOP, 2);
|
||||
BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
|
||||
const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK);
|
||||
const int cd_vert_node_offset = CustomData_get_offset(&bvh->bm->vdata, CD_DYNTOPO_NODE);
|
||||
const int cd_face_node_offset = CustomData_get_offset(&bvh->bm->pdata, CD_DYNTOPO_NODE);
|
||||
const int cd_vert_node_offset = bvh->cd_vert_node_offset;
|
||||
const int cd_face_node_offset = bvh->cd_face_node_offset;
|
||||
|
||||
bool modified = false;
|
||||
int n;
|
||||
@@ -1312,9 +1312,6 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh)
|
||||
{
|
||||
int i;
|
||||
|
||||
const int cd_vert_node_offset = CustomData_get_offset(&bvh->bm->vdata, CD_DYNTOPO_NODE);
|
||||
const int cd_face_node_offset = CustomData_get_offset(&bvh->bm->pdata, CD_DYNTOPO_NODE);
|
||||
|
||||
for (i = 0; i < bvh->totnode; i++) {
|
||||
PBVHNode *n = &bvh->nodes[i];
|
||||
if (n->flag & PBVH_Leaf) {
|
||||
@@ -1323,7 +1320,7 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh)
|
||||
|
||||
/* Recursively split nodes that have gotten too many
|
||||
* elements */
|
||||
pbvh_bmesh_node_limit_ensure(bvh, i, cd_vert_node_offset, cd_face_node_offset);
|
||||
pbvh_bmesh_node_limit_ensure(bvh, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +162,8 @@ struct PBVH {
|
||||
BMesh *bm;
|
||||
float bm_max_edge_len;
|
||||
float bm_min_edge_len;
|
||||
int cd_vert_node_offset;
|
||||
int cd_face_node_offset;
|
||||
|
||||
struct BMLog *bm_log;
|
||||
};
|
||||
|
||||
@@ -4793,15 +4793,14 @@ void sculpt_pbvh_clear(Object *ob)
|
||||
BKE_object_free_derived_caches(ob);
|
||||
}
|
||||
|
||||
void sculpt_dyntopo_node_layers_reset(BMesh *bm)
|
||||
void sculpt_dyntopo_node_layers_reset(SculptSession *ss)
|
||||
{
|
||||
/* A bit lame, but for now just recreate the PBVH. The alternative
|
||||
* is to store changes to the PBVH in the undo stack. */
|
||||
BMFace *f;
|
||||
BMVert *v;
|
||||
BMIter iter;
|
||||
const int cd_vert_node_offset = CustomData_get_offset(&bm->vdata, CD_DYNTOPO_NODE);
|
||||
const int cd_face_node_offset = CustomData_get_offset(&bm->pdata, CD_DYNTOPO_NODE);
|
||||
BMesh *bm = ss->bm;
|
||||
int cd_vert_node_offset = ss->cd_vert_node_offset;
|
||||
int cd_face_node_offset = ss->cd_face_node_offset;
|
||||
|
||||
/* clear the elements of the node information */
|
||||
BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
@@ -4813,6 +4812,34 @@ void sculpt_dyntopo_node_layers_reset(BMesh *bm)
|
||||
}
|
||||
}
|
||||
|
||||
void sculpt_dyntopo_node_layers_add(SculptSession *ss)
|
||||
{
|
||||
int cd_node_layer_index;
|
||||
|
||||
char layer_id[] = "_dyntopo_node_id";
|
||||
|
||||
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
|
||||
if (cd_node_layer_index == -1) {
|
||||
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT, layer_id);
|
||||
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
|
||||
}
|
||||
|
||||
ss->cd_vert_node_offset = CustomData_get_n_offset(&ss->bm->vdata, CD_PROP_INT, cd_node_layer_index);
|
||||
|
||||
ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
|
||||
|
||||
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
|
||||
if (cd_node_layer_index == -1) {
|
||||
BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT, layer_id);
|
||||
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
|
||||
}
|
||||
|
||||
ss->cd_face_node_offset = CustomData_get_n_offset(&ss->bm->pdata, CD_PROP_INT, cd_node_layer_index);
|
||||
|
||||
ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
|
||||
}
|
||||
|
||||
|
||||
void sculpt_update_after_dynamic_topology_toggle(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
@@ -4845,8 +4872,9 @@ void sculpt_dynamic_topology_enable(bContext *C)
|
||||
BM_mesh_bm_from_me(ss->bm, me, true, true, ob->shapenr);
|
||||
sculpt_dynamic_topology_triangulate(ss->bm);
|
||||
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
|
||||
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_DYNTOPO_NODE);
|
||||
BM_data_layer_add(ss->bm, &ss->bm->pdata, CD_DYNTOPO_NODE);
|
||||
sculpt_dyntopo_node_layers_add(ss);
|
||||
/* make sure the data for existing faces are initialized */
|
||||
sculpt_dyntopo_node_layers_reset(ss);
|
||||
BM_mesh_normals_update(ss->bm);
|
||||
|
||||
/* Enable dynamic topology */
|
||||
@@ -5303,7 +5331,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
/* force rebuild of pbvh for better BB placement */
|
||||
sculpt_pbvh_clear(ob);
|
||||
sculpt_dyntopo_node_layers_reset(ss->bm);
|
||||
sculpt_dyntopo_node_layers_reset(ss);
|
||||
/* Redraw */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
||||
|
||||
|
||||
@@ -42,13 +42,13 @@
|
||||
|
||||
struct bContext;
|
||||
struct Brush;
|
||||
struct BMesh;
|
||||
struct KeyBlock;
|
||||
struct Mesh;
|
||||
struct MultiresModifierData;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
struct Sculpt;
|
||||
struct SculptSession;
|
||||
struct SculptStroke;
|
||||
struct SculptUndoNode;
|
||||
|
||||
@@ -68,7 +68,8 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
|
||||
|
||||
/* Dynamic topology */
|
||||
void sculpt_pbvh_clear(Object *ob);
|
||||
void sculpt_dyntopo_node_layers_reset(struct BMesh *bm);
|
||||
void sculpt_dyntopo_node_layers_reset(struct SculptSession *ss);
|
||||
void sculpt_dyntopo_node_layers_add(struct SculptSession *ss);
|
||||
void sculpt_update_after_dynamic_topology_toggle(bContext *C);
|
||||
void sculpt_dynamic_topology_enable(struct bContext *C);
|
||||
void sculpt_dynamic_topology_disable(struct bContext *C,
|
||||
|
||||
@@ -301,7 +301,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
|
||||
MEM_freeN(nodes);
|
||||
}
|
||||
else {
|
||||
sculpt_dyntopo_node_layers_reset(ss->bm);
|
||||
sculpt_dyntopo_node_layers_reset(ss);
|
||||
sculpt_pbvh_clear(ob);
|
||||
}
|
||||
}
|
||||
@@ -318,8 +318,7 @@ static void sculpt_undo_bmesh_enable(Object *ob,
|
||||
/* Create empty BMesh and enable logging */
|
||||
ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
|
||||
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
|
||||
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_DYNTOPO_NODE);
|
||||
BM_data_layer_add(ss->bm, &ss->bm->pdata, CD_DYNTOPO_NODE);
|
||||
sculpt_dyntopo_node_layers_add(ss);
|
||||
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
|
||||
|
||||
/* Restore the BMLog using saved entries */
|
||||
@@ -342,6 +341,9 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
|
||||
/* Restore the mesh from the first log entry */
|
||||
BM_log_redo(ss->bm, ss->bm_log);
|
||||
|
||||
/* reset layers for all bmesh data */
|
||||
sculpt_dyntopo_node_layers_reset(ss);
|
||||
|
||||
unode->applied = true;
|
||||
}
|
||||
}
|
||||
@@ -357,6 +359,9 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
|
||||
/* Restore the mesh from the last log entry */
|
||||
BM_log_undo(ss->bm, ss->bm_log);
|
||||
|
||||
/* reset layers for all bmesh data */
|
||||
sculpt_dyntopo_node_layers_reset(ss);
|
||||
|
||||
unode->applied = false;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -63,10 +63,9 @@ typedef struct CustomDataExternal {
|
||||
* layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */
|
||||
typedef struct CustomData {
|
||||
CustomDataLayer *layers; /* CustomDataLayers, ordered by type */
|
||||
int typemap[42]; /* runtime only! - maps types to indices of first layer of that type,
|
||||
int typemap[41]; /* runtime only! - maps types to indices of first layer of that type,
|
||||
* MUST be >= CD_NUMTYPES, but we cant use a define here.
|
||||
* Correct size is ensured in CustomData_update_typemap assert() */
|
||||
int pad;
|
||||
int totlayer, maxlayer; /* number of layers, size of layers array */
|
||||
int totsize; /* in editmode, total size of all data layers */
|
||||
struct BLI_mempool *pool; /* (BMesh Only): Memory pool for allocation of blocks */
|
||||
@@ -121,8 +120,7 @@ enum {
|
||||
CD_MLOOPTANGENT = 39,
|
||||
CD_TESSLOOPNORMAL = 40,
|
||||
|
||||
CD_DYNTOPO_NODE = 41,
|
||||
CD_NUMTYPES = 42
|
||||
CD_NUMTYPES = 41
|
||||
};
|
||||
|
||||
/* Bits for CustomDataMask */
|
||||
@@ -170,8 +168,6 @@ enum {
|
||||
#define CD_MASK_MLOOPTANGENT (1LL << CD_MLOOPTANGENT)
|
||||
#define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL)
|
||||
|
||||
#define CD_MASK_DYNTOPO_NODE (1LL << CD_DYNTOPO_NODE)
|
||||
|
||||
/* CustomData.flag */
|
||||
enum {
|
||||
/* Indicates layer should not be copied by CustomData_from_template or CustomData_copy_data */
|
||||
|
||||
Reference in New Issue
Block a user