Sculpt: Standardize face set undo steps, optimize memory usage
Currently the face set of every single face is saved for every sculpt undo step. When only changing the face sets of a small section of the mesh, this can be quite wasteful. It also makes face sets a special case compare to all other sculpt undo step types, which makes the whole system more complex and harder to improve. Fixes T101203. Reviewed By: Hans Goudey Differential Revision: https://developer.blender.org/D16224 Ref D16224
This commit is contained in:
parent
3f294a37f5
commit
df788ecfd9
Notes:
blender-bot
2023-05-25 18:08:30 +02:00
Referenced by issue #101203, Regression: Issues with undoing the visibility of face sets in sculpt mode Referenced by issue #108267, Regression: Face set undo give incorrect result
|
@ -162,6 +162,7 @@ PenaltyBreakString: 1000000
|
|||
ForEachMacros:
|
||||
- BEGIN_ANIMFILTER_SUBCHANNELS
|
||||
- BKE_pbvh_vertex_iter_begin
|
||||
- BKE_pbvh_face_iter_begin
|
||||
- BLI_FOREACH_SPARSE_RANGE
|
||||
- BLI_SMALLSTACK_ITER_BEGIN
|
||||
- BMO_ITER
|
||||
|
|
|
@ -69,14 +69,22 @@ struct PBVHPublic {
|
|||
* intptr_t's in structs.
|
||||
*/
|
||||
|
||||
/* A generic PBVH vertex.
|
||||
*
|
||||
* Note: in PBVH_GRIDS we consider the final grid points
|
||||
* to be vertices. This is not true of edges or faces which are pulled from
|
||||
* the base mesh.
|
||||
*/
|
||||
typedef struct PBVHVertRef {
|
||||
intptr_t i;
|
||||
} PBVHVertRef;
|
||||
|
||||
/* Note: edges in PBVH_GRIDS are always pulled from the base mesh.*/
|
||||
typedef struct PBVHEdgeRef {
|
||||
intptr_t i;
|
||||
} PBVHEdgeRef;
|
||||
|
||||
/* Note: faces in PBVH_GRIDS are always puled from the base mesh.*/
|
||||
typedef struct PBVHFaceRef {
|
||||
intptr_t i;
|
||||
} PBVHFaceRef;
|
||||
|
@ -434,6 +442,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
|||
void BKE_pbvh_node_mark_update(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_update_mask(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_update_color(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_update_face_sets(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_update_visibility(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_redraw(PBVHNode *node);
|
||||
|
@ -466,6 +475,11 @@ void BKE_pbvh_node_get_loops(PBVH *pbvh,
|
|||
const int **r_loop_indices,
|
||||
const struct MLoop **r_loops);
|
||||
|
||||
/* Get number of faces in the mesh; for PBVH_GRIDS the
|
||||
* number of base mesh faces is returned.
|
||||
*/
|
||||
int BKE_pbvh_num_faces(const PBVH *pbvh);
|
||||
|
||||
void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
|
||||
void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
|
||||
|
||||
|
@ -665,6 +679,57 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
|||
} \
|
||||
((void)0)
|
||||
|
||||
#define PBVH_FACE_ITER_VERTS_RESERVED 8
|
||||
|
||||
typedef struct PBVHFaceIter {
|
||||
PBVHFaceRef face;
|
||||
int index;
|
||||
bool *hide;
|
||||
int *face_set;
|
||||
int i;
|
||||
|
||||
PBVHVertRef *verts;
|
||||
int verts_num;
|
||||
|
||||
/* Private. */
|
||||
#ifdef __cplusplus
|
||||
private:
|
||||
#endif
|
||||
|
||||
PBVHVertRef verts_reserved_[PBVH_FACE_ITER_VERTS_RESERVED];
|
||||
const PBVHNode *node_;
|
||||
PBVHType pbvh_type_;
|
||||
int verts_size_;
|
||||
GSetIterator bm_faces_iter_;
|
||||
int cd_hide_poly_, cd_face_set_;
|
||||
bool *hide_poly_;
|
||||
int *face_sets_;
|
||||
const struct MPoly *mpoly_;
|
||||
const struct MLoopTri *looptri_;
|
||||
const struct MLoop *mloop_;
|
||||
int prim_index_;
|
||||
const struct SubdivCCG *subdiv_ccg_;
|
||||
const struct BMesh *bm;
|
||||
|
||||
int last_face_index_;
|
||||
} PBVHFaceIter;
|
||||
|
||||
void BKE_pbvh_face_iter_init(PBVH *pbvh, PBVHNode *node, PBVHFaceIter *fd);
|
||||
void BKE_pbvh_face_iter_step(PBVHFaceIter *fd);
|
||||
bool BKE_pbvh_face_iter_done(PBVHFaceIter *fd);
|
||||
void BKE_pbvh_face_iter_finish(PBVHFaceIter *fd);
|
||||
|
||||
/** Iterate over faces inside a PBVHNode. These are either base mesh faces
|
||||
* (for PBVH_FACES and PBVH_GRIDS) or BMesh faces (for PBVH_BMESH).
|
||||
*/
|
||||
#define BKE_pbvh_face_iter_begin(pbvh, node, fd) \
|
||||
BKE_pbvh_face_iter_init(pbvh, node, &fd); \
|
||||
for (; !BKE_pbvh_face_iter_done(&fd); BKE_pbvh_face_iter_step(&fd)) {
|
||||
|
||||
#define BKE_pbvh_face_iter_end(fd) \
|
||||
} \
|
||||
BKE_pbvh_face_iter_finish(&fd)
|
||||
|
||||
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count);
|
||||
void BKE_pbvh_node_free_proxies(PBVHNode *node);
|
||||
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);
|
||||
|
|
|
@ -746,6 +746,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
|
|||
pbvh->vdata = vdata;
|
||||
pbvh->ldata = ldata;
|
||||
pbvh->pdata = pdata;
|
||||
pbvh->faces_num = mesh->totpoly;
|
||||
|
||||
pbvh->face_sets_color_seed = mesh->face_sets_color_seed;
|
||||
pbvh->face_sets_color_default = mesh->face_sets_color_default;
|
||||
|
@ -833,6 +834,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
|
|||
pbvh->gridkey = *key;
|
||||
pbvh->grid_hidden = grid_hidden;
|
||||
pbvh->subdiv_ccg = subdiv_ccg;
|
||||
pbvh->faces_num = me->totpoly;
|
||||
|
||||
/* Find maximum number of grids per face. */
|
||||
int max_grids = 1;
|
||||
|
@ -853,6 +855,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
|
|||
pbvh->ldata = &me->ldata;
|
||||
pbvh->pdata = &me->pdata;
|
||||
|
||||
pbvh->mpoly = BKE_mesh_polys(me);
|
||||
pbvh->mloop = BKE_mesh_loops(me);
|
||||
|
||||
/* We also need the base mesh for PBVH draw. */
|
||||
pbvh->mesh = me;
|
||||
|
||||
|
@ -2015,6 +2020,11 @@ void BKE_pbvh_node_mark_update_color(PBVHNode *node)
|
|||
node->flag |= PBVH_UpdateColor | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
|
||||
}
|
||||
|
||||
void BKE_pbvh_node_mark_update_face_sets(PBVHNode *node)
|
||||
{
|
||||
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
|
||||
}
|
||||
|
||||
void BKE_pbvh_mark_rebuild_pixels(PBVH *pbvh)
|
||||
{
|
||||
for (int n = 0; n < pbvh->totnode; n++) {
|
||||
|
@ -2119,6 +2129,20 @@ void BKE_pbvh_node_get_loops(PBVH *pbvh,
|
|||
}
|
||||
}
|
||||
|
||||
int BKE_pbvh_num_faces(const PBVH *pbvh)
|
||||
{
|
||||
switch (pbvh->header.type) {
|
||||
case PBVH_GRIDS:
|
||||
case PBVH_FACES:
|
||||
return pbvh->faces_num;
|
||||
case PBVH_BMESH:
|
||||
return pbvh->header.bm->totface;
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BKE_pbvh_node_get_verts(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
const int **r_vert_indices,
|
||||
|
@ -3611,3 +3635,184 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_face_iter_verts_reserve(PBVHFaceIter *fd, int verts_num)
|
||||
{
|
||||
if (verts_num >= fd->verts_size_) {
|
||||
fd->verts_size_ = (verts_num + 1) << 2;
|
||||
|
||||
if (fd->verts != fd->verts_reserved_) {
|
||||
MEM_SAFE_FREE(fd->verts);
|
||||
}
|
||||
|
||||
fd->verts = MEM_malloc_arrayN(fd->verts_size_, sizeof(void *), __func__);
|
||||
}
|
||||
|
||||
fd->verts_num = verts_num;
|
||||
}
|
||||
|
||||
BLI_INLINE int face_iter_prim_to_face(PBVHFaceIter *fd, int prim_index)
|
||||
{
|
||||
if (fd->subdiv_ccg_) {
|
||||
return BKE_subdiv_ccg_grid_to_face_index(fd->subdiv_ccg_, prim_index);
|
||||
}
|
||||
else {
|
||||
return fd->looptri_[prim_index].poly;
|
||||
}
|
||||
}
|
||||
|
||||
void pbvh_face_iter_step(PBVHFaceIter *fd, bool do_step)
|
||||
{
|
||||
if (do_step) {
|
||||
fd->i++;
|
||||
}
|
||||
|
||||
switch (fd->pbvh_type_) {
|
||||
case PBVH_BMESH: {
|
||||
if (do_step) {
|
||||
BLI_gsetIterator_step(&fd->bm_faces_iter_);
|
||||
if (BLI_gsetIterator_done(&fd->bm_faces_iter_)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BMFace *f = (BMFace *)BLI_gsetIterator_getKey(&fd->bm_faces_iter_);
|
||||
fd->face.i = (intptr_t)f;
|
||||
fd->index = f->head.index;
|
||||
|
||||
if (fd->cd_face_set_ != -1) {
|
||||
fd->face_set = (int *)BM_ELEM_CD_GET_VOID_P(f, fd->cd_face_set_);
|
||||
}
|
||||
|
||||
if (fd->cd_hide_poly_ != -1) {
|
||||
fd->hide = (bool *)BM_ELEM_CD_GET_VOID_P(f, fd->cd_hide_poly_);
|
||||
}
|
||||
|
||||
pbvh_face_iter_verts_reserve(fd, f->len);
|
||||
int vertex_i = 0;
|
||||
|
||||
BMLoop *l = f->l_first;
|
||||
do {
|
||||
fd->verts[vertex_i++].i = (intptr_t)l->v;
|
||||
} while ((l = l->next) != f->l_first);
|
||||
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS:
|
||||
case PBVH_FACES: {
|
||||
int face_index = 0;
|
||||
|
||||
if (do_step) {
|
||||
fd->prim_index_++;
|
||||
|
||||
while (fd->prim_index_ < fd->node_->totprim) {
|
||||
face_index = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]);
|
||||
|
||||
if (face_index != fd->last_face_index_) {
|
||||
break;
|
||||
}
|
||||
|
||||
fd->prim_index_++;
|
||||
}
|
||||
}
|
||||
else if (fd->prim_index_ < fd->node_->totprim) {
|
||||
face_index = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]);
|
||||
}
|
||||
|
||||
if (fd->prim_index_ >= fd->node_->totprim) {
|
||||
return;
|
||||
}
|
||||
|
||||
fd->last_face_index_ = face_index;
|
||||
const MPoly *mp = fd->mpoly_ + face_index;
|
||||
|
||||
fd->face.i = fd->index = face_index;
|
||||
|
||||
if (fd->face_sets_) {
|
||||
fd->face_set = fd->face_sets_ + face_index;
|
||||
}
|
||||
if (fd->hide_poly_) {
|
||||
fd->hide = fd->hide_poly_ + face_index;
|
||||
}
|
||||
|
||||
pbvh_face_iter_verts_reserve(fd, mp->totloop);
|
||||
|
||||
const MLoop *ml = fd->mloop_ + mp->loopstart;
|
||||
for (int i = 0; i < mp->totloop; i++, ml++) {
|
||||
if (fd->pbvh_type_ == PBVH_GRIDS) {
|
||||
/* Grid corners. */
|
||||
fd->verts[i].i = mp->loopstart + i;
|
||||
}
|
||||
else {
|
||||
fd->verts[i].i = ml->v;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_pbvh_face_iter_step(PBVHFaceIter *fd)
|
||||
{
|
||||
pbvh_face_iter_step(fd, true);
|
||||
}
|
||||
|
||||
void BKE_pbvh_face_iter_init(PBVH *pbvh, PBVHNode *node, PBVHFaceIter *fd)
|
||||
{
|
||||
memset(fd, 0, sizeof(*fd));
|
||||
|
||||
fd->node_ = node;
|
||||
fd->pbvh_type_ = BKE_pbvh_type(pbvh);
|
||||
|
||||
fd->verts = fd->verts_reserved_;
|
||||
fd->verts_size_ = PBVH_FACE_ITER_VERTS_RESERVED;
|
||||
|
||||
switch (BKE_pbvh_type(pbvh)) {
|
||||
case PBVH_GRIDS:
|
||||
fd->subdiv_ccg_ = pbvh->subdiv_ccg;
|
||||
case PBVH_FACES:
|
||||
fd->mpoly_ = pbvh->mpoly;
|
||||
fd->mloop_ = pbvh->mloop;
|
||||
fd->looptri_ = pbvh->looptri;
|
||||
fd->hide_poly_ = pbvh->hide_poly;
|
||||
fd->face_sets_ = pbvh->face_sets;
|
||||
fd->last_face_index_ = -1;
|
||||
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
fd->bm = pbvh->header.bm;
|
||||
fd->cd_face_set_ = CustomData_get_offset_named(
|
||||
&pbvh->header.bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
fd->cd_hide_poly_ = CustomData_get_offset_named(
|
||||
&pbvh->header.bm->pdata, CD_PROP_INT32, ".hide_poly");
|
||||
|
||||
BLI_gsetIterator_init(&fd->bm_faces_iter_, node->bm_faces);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!BKE_pbvh_face_iter_done(fd)) {
|
||||
pbvh_face_iter_step(fd, false);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_pbvh_face_iter_finish(PBVHFaceIter *fd)
|
||||
{
|
||||
if (fd->verts != fd->verts_reserved_) {
|
||||
MEM_SAFE_FREE(fd->verts);
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_pbvh_face_iter_done(PBVHFaceIter *fd)
|
||||
{
|
||||
switch (fd->pbvh_type_) {
|
||||
case PBVH_FACES:
|
||||
case PBVH_GRIDS:
|
||||
return fd->prim_index_ >= fd->node_->totprim;
|
||||
case PBVH_BMESH:
|
||||
return BLI_gsetIterator_done(&fd->bm_faces_iter_);
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ struct PBVH {
|
|||
int *prim_indices;
|
||||
int totprim;
|
||||
int totvert;
|
||||
int faces_num; /* Do not use directly, use BKE_pbvh_num_faces. */
|
||||
|
||||
int leaf_limit;
|
||||
|
||||
|
|
|
@ -663,10 +663,11 @@ static bool sculpt_gesture_is_effected_lasso(SculptGestureContext *sgcontext, co
|
|||
return BLI_BITMAP_TEST_BOOL(lasso->mask_px, scr_co_s[1] * lasso->width + scr_co_s[0]);
|
||||
}
|
||||
|
||||
static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, PBVHVertexIter *vd)
|
||||
static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, PBVHVertRef vertex)
|
||||
{
|
||||
float vertex_normal[3];
|
||||
SCULPT_vertex_normal_get(sgcontext->ss, vd->vertex, vertex_normal);
|
||||
const float *co = SCULPT_vertex_co_get(sgcontext->ss, vertex);
|
||||
SCULPT_vertex_normal_get(sgcontext->ss, vertex, vertex_normal);
|
||||
float dot = dot_v3v3(sgcontext->view_normal, vertex_normal);
|
||||
const bool is_effected_front_face = !(sgcontext->front_faces_only && dot < 0.0f);
|
||||
|
||||
|
@ -676,20 +677,31 @@ static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, P
|
|||
|
||||
switch (sgcontext->shape_type) {
|
||||
case SCULPT_GESTURE_SHAPE_BOX:
|
||||
return isect_point_planes_v3(sgcontext->clip_planes, 4, vd->co);
|
||||
return isect_point_planes_v3(sgcontext->clip_planes, 4, co);
|
||||
case SCULPT_GESTURE_SHAPE_LASSO:
|
||||
return sculpt_gesture_is_effected_lasso(sgcontext, vd->co);
|
||||
return sculpt_gesture_is_effected_lasso(sgcontext, co);
|
||||
case SCULPT_GESTURE_SHAPE_LINE:
|
||||
if (sgcontext->line.use_side_planes) {
|
||||
return plane_point_side_v3(sgcontext->line.plane, vd->co) > 0.0f &&
|
||||
plane_point_side_v3(sgcontext->line.side_plane[0], vd->co) > 0.0f &&
|
||||
plane_point_side_v3(sgcontext->line.side_plane[1], vd->co) > 0.0f;
|
||||
return plane_point_side_v3(sgcontext->line.plane, co) > 0.0f &&
|
||||
plane_point_side_v3(sgcontext->line.side_plane[0], co) > 0.0f &&
|
||||
plane_point_side_v3(sgcontext->line.side_plane[1], co) > 0.0f;
|
||||
}
|
||||
return plane_point_side_v3(sgcontext->line.plane, vd->co) > 0.0f;
|
||||
return plane_point_side_v3(sgcontext->line.plane, co) > 0.0f;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool sculpt_gesture_is_face_effected(SculptGestureContext *sgcontext, PBVHFaceIter *fd)
|
||||
{
|
||||
for (int i = 0; i < fd->verts_num; i++) {
|
||||
if (sculpt_gesture_is_vertex_effected(sgcontext, fd->verts[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void sculpt_gesture_apply(bContext *C, SculptGestureContext *sgcontext, wmOperator *op)
|
||||
{
|
||||
SculptGestureOperation *operation = sgcontext->operation;
|
||||
|
@ -728,9 +740,6 @@ static void sculpt_gesture_face_set_begin(bContext *C, SculptGestureContext *sgc
|
|||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, sgcontext->vc.obact, true, false, false);
|
||||
|
||||
/* Face Sets modifications do a single undo push. */
|
||||
SCULPT_undo_push_node(sgcontext->vc.obact, NULL, SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
|
||||
static void face_set_gesture_apply_task_cb(void *__restrict userdata,
|
||||
|
@ -741,16 +750,18 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata,
|
|||
SculptGestureFaceSetOperation *face_set_operation = (SculptGestureFaceSetOperation *)
|
||||
sgcontext->operation;
|
||||
PBVHNode *node = sgcontext->nodes[i];
|
||||
PBVHVertexIter vd;
|
||||
bool any_updated = false;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
|
||||
SCULPT_vertex_face_set_set(sgcontext->ss, vd.vertex, face_set_operation->new_face_set_id);
|
||||
SCULPT_undo_push_node(sgcontext->vc.obact, node, SCULPT_UNDO_FACE_SETS);
|
||||
|
||||
PBVHFaceIter fd;
|
||||
BKE_pbvh_face_iter_begin (sgcontext->ss->pbvh, node, fd) {
|
||||
if (sculpt_gesture_is_face_effected(sgcontext, &fd)) {
|
||||
SCULPT_face_set_set(sgcontext->ss, fd.face, face_set_operation->new_face_set_id);
|
||||
any_updated = true;
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
BKE_pbvh_face_iter_end(fd);
|
||||
|
||||
if (any_updated) {
|
||||
BKE_pbvh_node_mark_update_visibility(node);
|
||||
|
@ -821,7 +832,7 @@ static void mask_gesture_apply_task_cb(void *__restrict userdata,
|
|||
bool redraw = false;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
|
||||
if (sculpt_gesture_is_vertex_effected(sgcontext, vd.vertex)) {
|
||||
float prevmask = vd.mask ? *vd.mask : 0.0f;
|
||||
if (!any_masked) {
|
||||
any_masked = true;
|
||||
|
@ -1442,7 +1453,7 @@ static void project_line_gesture_apply_task_cb(void *__restrict userdata,
|
|||
SCULPT_undo_push_node(sgcontext->vc.obact, node, SCULPT_UNDO_COORDS);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
if (!sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
|
||||
if (!sculpt_gesture_is_vertex_effected(sgcontext, vd.vertex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1399,6 +1399,39 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter
|
|||
}
|
||||
}
|
||||
|
||||
void SCULPT_orig_face_data_unode_init(SculptOrigFaceData *data, Object *ob, SculptUndoNode *unode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
BMesh *bm = ss->bm;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->unode = unode;
|
||||
|
||||
if (bm) {
|
||||
data->bm_log = ss->bm_log;
|
||||
}
|
||||
else {
|
||||
data->face_sets = unode->face_sets;
|
||||
}
|
||||
}
|
||||
|
||||
void SCULPT_orig_face_data_init(SculptOrigFaceData *data,
|
||||
Object *ob,
|
||||
PBVHNode *node,
|
||||
SculptUndoType type)
|
||||
{
|
||||
SculptUndoNode *unode;
|
||||
unode = SCULPT_undo_push_node(ob, node, type);
|
||||
SCULPT_orig_face_data_unode_init(data, ob, unode);
|
||||
}
|
||||
|
||||
void SCULPT_orig_face_data_update(SculptOrigFaceData *orig_data, PBVHFaceIter *iter)
|
||||
{
|
||||
if (orig_data->unode->type == SCULPT_UNDO_FACE_SETS) {
|
||||
orig_data->face_set = orig_data->face_sets ? orig_data->face_sets[iter->i] : false;
|
||||
}
|
||||
}
|
||||
|
||||
static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3])
|
||||
{
|
||||
float rake_dist = len_v3v3(srd->follow_co, co);
|
||||
|
@ -1450,6 +1483,9 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
|
|||
case SCULPT_TOOL_SMEAR:
|
||||
type = SCULPT_UNDO_COLOR;
|
||||
break;
|
||||
case SCULPT_TOOL_DRAW_FACE_SETS:
|
||||
type = ss->cache->alt_smooth ? SCULPT_UNDO_COORDS : SCULPT_UNDO_FACE_SETS;
|
||||
break;
|
||||
default:
|
||||
type = SCULPT_UNDO_COORDS;
|
||||
break;
|
||||
|
@ -1473,6 +1509,9 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
|
|||
case SCULPT_UNDO_COLOR:
|
||||
BKE_pbvh_node_mark_update_color(data->nodes[n]);
|
||||
break;
|
||||
case SCULPT_UNDO_FACE_SETS:
|
||||
BKE_pbvh_node_mark_update_face_sets(data->nodes[n]);
|
||||
break;
|
||||
case SCULPT_UNDO_COORDS:
|
||||
BKE_pbvh_node_mark_update(data->nodes[n]);
|
||||
break;
|
||||
|
@ -1481,30 +1520,50 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
|
|||
}
|
||||
|
||||
PBVHVertexIter vd;
|
||||
SculptOrigVertData orig_data;
|
||||
SculptOrigVertData orig_vert_data;
|
||||
SculptOrigFaceData orig_face_data;
|
||||
|
||||
SCULPT_orig_vert_data_unode_init(&orig_data, data->ob, unode);
|
||||
if (type != SCULPT_UNDO_FACE_SETS) {
|
||||
SCULPT_orig_vert_data_unode_init(&orig_vert_data, data->ob, unode);
|
||||
}
|
||||
else {
|
||||
SCULPT_orig_face_data_unode_init(&orig_face_data, data->ob, unode);
|
||||
}
|
||||
|
||||
if (unode->type == SCULPT_UNDO_FACE_SETS) {
|
||||
PBVHFaceIter fd;
|
||||
BKE_pbvh_face_iter_begin (ss->pbvh, data->nodes[n], fd) {
|
||||
SCULPT_orig_face_data_update(&orig_face_data, &fd);
|
||||
|
||||
if (fd.face_set) {
|
||||
*fd.face_set = orig_face_data.face_set;
|
||||
}
|
||||
}
|
||||
|
||||
BKE_pbvh_face_iter_end(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_data, &vd);
|
||||
SCULPT_orig_vert_data_update(&orig_vert_data, &vd);
|
||||
|
||||
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
|
||||
copy_v3_v3(vd.co, orig_data.co);
|
||||
if (orig_vert_data.unode->type == SCULPT_UNDO_COORDS) {
|
||||
copy_v3_v3(vd.co, orig_vert_data.co);
|
||||
if (vd.no) {
|
||||
copy_v3_v3(vd.no, orig_data.no);
|
||||
copy_v3_v3(vd.no, orig_vert_data.no);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(vd.fno, orig_data.no);
|
||||
copy_v3_v3(vd.fno, orig_vert_data.no);
|
||||
}
|
||||
if (vd.mvert) {
|
||||
BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
|
||||
}
|
||||
}
|
||||
else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
|
||||
*vd.mask = orig_data.mask;
|
||||
else if (orig_vert_data.unode->type == SCULPT_UNDO_MASK) {
|
||||
*vd.mask = orig_vert_data.mask;
|
||||
}
|
||||
else if (orig_data.unode->type == SCULPT_UNDO_COLOR) {
|
||||
SCULPT_vertex_color_set(ss, vd.vertex, orig_data.col);
|
||||
else if (orig_vert_data.unode->type == SCULPT_UNDO_COLOR) {
|
||||
SCULPT_vertex_color_set(ss, vd.vertex, orig_vert_data.col);
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
@ -3296,13 +3355,16 @@ static void do_brush_action_task_cb(void *__restrict userdata,
|
|||
|
||||
bool need_coords = ss->cache->supports_gravity;
|
||||
|
||||
/* Face Sets modifications do a single undo push */
|
||||
if (data->brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) {
|
||||
BKE_pbvh_node_mark_redraw(data->nodes[n]);
|
||||
BKE_pbvh_node_mark_update_face_sets(data->nodes[n]);
|
||||
|
||||
/* Draw face sets in smooth mode moves the vertices. */
|
||||
if (ss->cache->alt_smooth) {
|
||||
need_coords = true;
|
||||
}
|
||||
else {
|
||||
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
}
|
||||
else if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) {
|
||||
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
|
||||
|
@ -3380,14 +3442,6 @@ static void do_brush_action(Sculpt *sd,
|
|||
* and the number of nodes under the brush influence. */
|
||||
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS &&
|
||||
SCULPT_stroke_is_first_brush_step(ss->cache) && !ss->cache->alt_smooth) {
|
||||
|
||||
/* Dynamic-topology does not support Face Sets data, so it can't store/restore it from undo. */
|
||||
/* TODO(pablodp606): This check should be done in the undo code and not here, but the rest of
|
||||
* the sculpt code is not checking for unsupported undo types that may return a null node. */
|
||||
if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
|
||||
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
|
||||
if (ss->cache->invert) {
|
||||
/* When inverting the brush, pick the paint face mask ID from the mesh. */
|
||||
ss->cache->paint_face_set = SCULPT_active_face_set_get(ss);
|
||||
|
@ -5217,13 +5271,6 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
|
|||
BKE_brush_use_size_pressure(brush)) ||
|
||||
(brush->flag & BRUSH_DRAG_DOT)) {
|
||||
|
||||
SculptUndoNode *unode = SCULPT_undo_get_first_node();
|
||||
if (unode && unode->type == SCULPT_UNDO_FACE_SETS) {
|
||||
for (int i = 0; i < ss->totfaces; i++) {
|
||||
ss->face_sets[i] = unode->face_sets[i];
|
||||
}
|
||||
}
|
||||
|
||||
paint_mesh_restore_co(sd, ob);
|
||||
|
||||
if (ss->cache) {
|
||||
|
@ -6195,4 +6242,30 @@ void SCULPT_stroke_id_ensure(Object *ob)
|
|||
}
|
||||
}
|
||||
|
||||
int SCULPT_face_set_get(const SculptSession *ss, PBVHFaceRef face)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_BMESH:
|
||||
return 0;
|
||||
case PBVH_FACES:
|
||||
case PBVH_GRIDS:
|
||||
return ss->face_sets[face.i];
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SCULPT_face_set_set(SculptSession *ss, PBVHFaceRef face, int fset)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_BMESH:
|
||||
break;
|
||||
case PBVH_FACES:
|
||||
case PBVH_GRIDS:
|
||||
ss->face_sets[face.i] = fset;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -545,7 +545,11 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
|
|||
}
|
||||
|
||||
if (automasking->settings.flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) {
|
||||
if (!SCULPT_vertex_has_unique_face_set(ss, vert)) {
|
||||
bool ignore = ss->cache && ss->cache->brush &&
|
||||
ss->cache->brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS &&
|
||||
SCULPT_vertex_face_set_get(ss, vert) == ss->cache->paint_face_set;
|
||||
|
||||
if (!ignore && !SCULPT_vertex_has_unique_face_set(ss, vert)) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2074,7 +2074,9 @@ static void sculpt_expand_undo_push(Object *ob, ExpandCache *expand_cache)
|
|||
}
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_FACE_SETS:
|
||||
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
|
||||
for (int i = 0; i < totnode; i++) {
|
||||
SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_COLORS:
|
||||
for (int i = 0; i < totnode; i++) {
|
||||
|
|
|
@ -125,6 +125,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
SCULPT_automasking_node_begin(
|
||||
data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
|
||||
|
||||
bool changed = false;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_automasking_node_update(ss, &automask_data, &vd);
|
||||
|
||||
|
@ -156,6 +157,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
if (fade > 0.05f) {
|
||||
ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,10 +178,15 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
if (fade > 0.05f) {
|
||||
SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
if (changed) {
|
||||
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
||||
|
@ -344,7 +351,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
SCULPT_undo_push_begin(ob, op);
|
||||
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
|
||||
for (const int i : blender::IndexRange(totnode)) {
|
||||
SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
|
||||
const int next_face_set = SCULPT_face_set_next_available_get(ss);
|
||||
|
||||
|
@ -637,7 +646,9 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
SCULPT_undo_push_begin(ob, op);
|
||||
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
|
||||
for (const int i : blender::IndexRange(totnode)) {
|
||||
SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
|
||||
const float threshold = RNA_float_get(op->ptr, "threshold");
|
||||
|
||||
|
@ -1366,7 +1377,9 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob,
|
|||
return;
|
||||
}
|
||||
SCULPT_undo_push_begin(ob, op);
|
||||
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
|
||||
for (const int i : blender::IndexRange(totnode)) {
|
||||
SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden);
|
||||
SCULPT_undo_push_end(ob);
|
||||
face_set_edit_do_post_visibility_updates(ob, nodes, totnode);
|
||||
|
|
|
@ -98,6 +98,13 @@ typedef struct {
|
|||
const float *col;
|
||||
} SculptOrigVertData;
|
||||
|
||||
typedef struct SculptOrigFaceData {
|
||||
struct SculptUndoNode *unode;
|
||||
struct BMLog *bm_log;
|
||||
const int *face_sets;
|
||||
int face_set;
|
||||
} SculptOrigFaceData;
|
||||
|
||||
/* Flood Fill. */
|
||||
typedef struct {
|
||||
GSQueue *queue;
|
||||
|
@ -201,6 +208,9 @@ typedef struct SculptUndoNode {
|
|||
/* Sculpt Face Sets */
|
||||
int *face_sets;
|
||||
|
||||
PBVHFaceRef *faces;
|
||||
int faces_num;
|
||||
|
||||
size_t undo_size;
|
||||
} SculptUndoNode;
|
||||
|
||||
|
@ -1034,6 +1044,9 @@ int SCULPT_active_face_set_get(SculptSession *ss);
|
|||
int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex);
|
||||
void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set);
|
||||
|
||||
int SCULPT_face_set_get(const SculptSession *ss, PBVHFaceRef face);
|
||||
void SCULPT_face_set_set(SculptSession *ss, PBVHFaceRef face, int fset);
|
||||
|
||||
bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set);
|
||||
bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex);
|
||||
|
||||
|
@ -1066,6 +1079,25 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter
|
|||
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
|
||||
Object *ob,
|
||||
struct SculptUndoNode *unode);
|
||||
/**
|
||||
* Initialize a #SculptOrigFaceData for accessing original face data;
|
||||
* handles #BMesh, #Mesh, and multi-resolution.
|
||||
*/
|
||||
void SCULPT_orig_face_data_init(SculptOrigFaceData *data,
|
||||
Object *ob,
|
||||
PBVHNode *node,
|
||||
SculptUndoType type);
|
||||
/**
|
||||
* Update a #SculptOrigFaceData for a particular vertex from the PBVH iterator.
|
||||
*/
|
||||
void SCULPT_orig_face_data_update(SculptOrigFaceData *orig_data, PBVHFaceIter *iter);
|
||||
/**
|
||||
* Initialize a #SculptOrigVertData for accessing original vertex data;
|
||||
* handles #BMesh, #Mesh, and multi-resolution.
|
||||
*/
|
||||
void SCULPT_orig_face_data_unode_init(SculptOrigFaceData *data,
|
||||
Object *ob,
|
||||
struct SculptUndoNode *unode);
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -86,6 +86,8 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
|
|||
PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss);
|
||||
int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, active_vertex);
|
||||
|
||||
bool face_sets_changed = false;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
|
||||
int vi = vd.index;
|
||||
float final_mask = *vd.mask;
|
||||
|
@ -111,6 +113,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
|
|||
if (data->mask_expand_create_face_set) {
|
||||
if (final_mask == 1.0f) {
|
||||
SCULPT_vertex_face_set_set(ss, vd.vertex, ss->filter_cache->new_face_set);
|
||||
face_sets_changed = true;
|
||||
}
|
||||
BKE_pbvh_node_mark_redraw(node);
|
||||
}
|
||||
|
@ -131,6 +134,10 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
|
|||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
if (face_sets_changed) {
|
||||
SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
}
|
||||
|
||||
static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
|
@ -353,9 +360,9 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
|
|||
SCULPT_undo_push_begin(ob, op);
|
||||
|
||||
if (create_face_set) {
|
||||
SCULPT_undo_push_node(ob, ss->filter_cache->nodes[0], SCULPT_UNDO_FACE_SETS);
|
||||
for (int i = 0; i < ss->filter_cache->totnode; i++) {
|
||||
BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
|
||||
SCULPT_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_FACE_SETS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -292,6 +292,7 @@ struct PartialUpdateData {
|
|||
bool *modified_hidden_verts;
|
||||
bool *modified_mask_verts;
|
||||
bool *modified_color_verts;
|
||||
bool *modified_face_set_faces;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -350,6 +351,16 @@ static void update_cb_partial(PBVHNode *node, void *userdata)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (data->modified_face_set_faces) {
|
||||
PBVHFaceIter fd;
|
||||
BKE_pbvh_face_iter_begin (data->pbvh, node, fd) {
|
||||
if (data->modified_face_set_faces[fd.index]) {
|
||||
BKE_pbvh_node_mark_update_face_sets(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
BKE_pbvh_face_iter_end(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static bool test_swap_v3_v3(float a[3], float b[3])
|
||||
|
@ -600,24 +611,32 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode, bool *m
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode)
|
||||
static bool sculpt_undo_restore_face_sets(bContext *C,
|
||||
SculptUndoNode *unode,
|
||||
bool *modified_face_set_faces)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(view_layer);
|
||||
Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
int *face_sets = CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
if (!face_sets) {
|
||||
face_sets = CustomData_add_layer_named(
|
||||
&me->pdata, CD_PROP_INT32, CD_CONSTRUCT, NULL, me->totpoly, ".sculpt_face_set");
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(me);
|
||||
BKE_pbvh_face_sets_set(ss->pbvh, ss->face_sets);
|
||||
|
||||
bool modified = false;
|
||||
|
||||
for (int i = 0; i < unode->faces_num; i++) {
|
||||
int face_index = unode->faces[i].i;
|
||||
|
||||
SWAP(int, unode->face_sets[i], ss->face_sets[face_index]);
|
||||
|
||||
modified_face_set_faces[face_index] = unode->face_sets[i] != ss->face_sets[face_index];
|
||||
modified |= modified_face_set_faces[face_index];
|
||||
}
|
||||
|
||||
for (int i = 0; i < me->totpoly; i++) {
|
||||
SWAP(int, face_sets[i], unode->face_sets[i]);
|
||||
}
|
||||
return false;
|
||||
return modified;
|
||||
}
|
||||
|
||||
static void sculpt_undo_bmesh_restore_generic_task_cb(
|
||||
|
@ -864,6 +883,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
|
||||
SculptUndoNode *unode;
|
||||
bool update = false, rebuild = false, update_mask = false, update_visibility = false;
|
||||
bool update_face_sets = false;
|
||||
bool need_mask = false;
|
||||
bool need_refine_subdiv = false;
|
||||
bool clear_automask_cache = false;
|
||||
|
@ -892,34 +912,6 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
|
||||
|
||||
if (lb->first) {
|
||||
unode = lb->first;
|
||||
if (unode->type == SCULPT_UNDO_FACE_SETS) {
|
||||
sculpt_undo_restore_face_sets(C, unode);
|
||||
|
||||
rebuild = true;
|
||||
BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask, false);
|
||||
|
||||
SCULPT_visibility_sync_all_from_faces(ob);
|
||||
|
||||
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
|
||||
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
|
||||
BKE_mesh_flush_hidden_from_verts(ob->data);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
|
||||
if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
unode->applied = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (lb->first != NULL) {
|
||||
/* Only do early object update for edits if first node needs this.
|
||||
* Undo steps like geometry does not need object to be updated before they run and will
|
||||
|
@ -934,12 +926,13 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
}
|
||||
}
|
||||
|
||||
/* The PBVH already keeps track of which vertices need updated normals, but it doesn't keep track
|
||||
* of other updated. In order to tell the corresponding PBVH nodes to update, keep track of which
|
||||
* elements were updated for specific layers. */
|
||||
/* The PBVH already keeps track of which vertices need updated normals, but it doesn't keep
|
||||
* track of other updated. In order to tell the corresponding PBVH nodes to update, keep track
|
||||
* of which elements were updated for specific layers. */
|
||||
bool *modified_hidden_verts = NULL;
|
||||
bool *modified_mask_verts = NULL;
|
||||
bool *modified_color_verts = NULL;
|
||||
bool *modified_face_set_faces = NULL;
|
||||
char *undo_modified_grids = NULL;
|
||||
bool use_multires_undo = false;
|
||||
|
||||
|
@ -990,6 +983,14 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
}
|
||||
break;
|
||||
case SCULPT_UNDO_FACE_SETS:
|
||||
if (modified_face_set_faces == NULL) {
|
||||
modified_face_set_faces = MEM_calloc_arrayN(
|
||||
BKE_pbvh_num_faces(ss->pbvh), sizeof(bool), __func__);
|
||||
}
|
||||
if (sculpt_undo_restore_face_sets(C, unode, modified_face_set_faces)) {
|
||||
update = true;
|
||||
update_face_sets = true;
|
||||
}
|
||||
break;
|
||||
case SCULPT_UNDO_COLOR:
|
||||
if (modified_color_verts == NULL) {
|
||||
|
@ -1049,6 +1050,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
.modified_hidden_verts = modified_hidden_verts,
|
||||
.modified_mask_verts = modified_mask_verts,
|
||||
.modified_color_verts = modified_color_verts,
|
||||
.modified_face_set_faces = modified_face_set_faces,
|
||||
};
|
||||
BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
|
||||
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw);
|
||||
|
@ -1056,6 +1058,10 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
if (update_mask) {
|
||||
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
|
||||
}
|
||||
if (update_face_sets) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
|
||||
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_RebuildDrawBuffers);
|
||||
}
|
||||
|
||||
if (update_visibility) {
|
||||
if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_GRIDS)) {
|
||||
|
@ -1098,6 +1104,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
MEM_SAFE_FREE(modified_hidden_verts);
|
||||
MEM_SAFE_FREE(modified_mask_verts);
|
||||
MEM_SAFE_FREE(modified_color_verts);
|
||||
MEM_SAFE_FREE(modified_face_set_faces);
|
||||
MEM_SAFE_FREE(undo_modified_grids);
|
||||
}
|
||||
|
||||
|
@ -1121,6 +1128,9 @@ static void sculpt_undo_free_list(ListBase *lb)
|
|||
if (unode->index) {
|
||||
MEM_freeN(unode->index);
|
||||
}
|
||||
if (unode->faces) {
|
||||
MEM_freeN(unode->faces);
|
||||
}
|
||||
if (unode->loop_index) {
|
||||
MEM_freeN(unode->loop_index);
|
||||
}
|
||||
|
@ -1270,6 +1280,23 @@ static SculptUndoNode *sculpt_undo_find_or_alloc_node_type(Object *object, Sculp
|
|||
return sculpt_undo_alloc_node_type(object, type);
|
||||
}
|
||||
|
||||
static void sculpt_undo_store_faces(SculptSession *ss, SculptUndoNode *unode)
|
||||
{
|
||||
unode->faces_num = 0;
|
||||
|
||||
PBVHFaceIter fd;
|
||||
BKE_pbvh_face_iter_begin (ss->pbvh, unode->node, fd) {
|
||||
unode->faces_num++;
|
||||
}
|
||||
BKE_pbvh_face_iter_end(fd);
|
||||
|
||||
unode->faces = MEM_malloc_arrayN(sizeof(*unode->faces), unode->faces_num, __func__);
|
||||
BKE_pbvh_face_iter_begin (ss->pbvh, unode->node, fd) {
|
||||
unode->faces[fd.i] = fd.face;
|
||||
}
|
||||
BKE_pbvh_face_iter_end(fd);
|
||||
}
|
||||
|
||||
static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, SculptUndoType type)
|
||||
{
|
||||
UndoSculpt *usculpt = sculpt_undo_get_nodes();
|
||||
|
@ -1292,6 +1319,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
|
|||
}
|
||||
|
||||
bool need_loops = type == SCULPT_UNDO_COLOR;
|
||||
const bool need_faces = type == SCULPT_UNDO_FACE_SETS;
|
||||
|
||||
if (need_loops) {
|
||||
int totloop;
|
||||
|
@ -1306,6 +1334,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
|
|||
usculpt->undo_size += alloc_size;
|
||||
}
|
||||
|
||||
if (need_faces) {
|
||||
sculpt_undo_store_faces(ss, unode);
|
||||
const size_t alloc_size = sizeof(*unode->faces) * (size_t)unode->faces_num;
|
||||
usculpt->undo_size += alloc_size;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SCULPT_UNDO_COORDS: {
|
||||
size_t alloc_size = sizeof(*unode->co) * (size_t)allvert;
|
||||
|
@ -1356,9 +1390,14 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
|
|||
case SCULPT_UNDO_DYNTOPO_END:
|
||||
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
|
||||
BLI_assert_msg(0, "Dynamic topology should've already been handled");
|
||||
case SCULPT_UNDO_GEOMETRY:
|
||||
case SCULPT_UNDO_FACE_SETS:
|
||||
break;
|
||||
case SCULPT_UNDO_GEOMETRY:
|
||||
break;
|
||||
case SCULPT_UNDO_FACE_SETS: {
|
||||
const size_t alloc_size = sizeof(*unode->face_sets) * (size_t)unode->faces_num;
|
||||
usculpt->undo_size += alloc_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxgrid) {
|
||||
|
@ -1488,32 +1527,15 @@ static SculptUndoNode *sculpt_undo_geometry_push(Object *object, SculptUndoType
|
|||
return unode;
|
||||
}
|
||||
|
||||
static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType type)
|
||||
static void sculpt_undo_store_face_sets(SculptSession *ss, SculptUndoNode *unode)
|
||||
{
|
||||
UndoSculpt *usculpt = sculpt_undo_get_nodes();
|
||||
SculptUndoNode *unode = MEM_callocN(sizeof(*unode), __func__);
|
||||
unode->face_sets = MEM_malloc_arrayN(sizeof(*unode->face_sets), unode->faces_num, __func__);
|
||||
|
||||
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
|
||||
unode->type = type;
|
||||
unode->applied = true;
|
||||
|
||||
Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
|
||||
unode->face_sets = MEM_callocN(me->totpoly * sizeof(int), "sculpt face sets");
|
||||
|
||||
const int *face_sets = CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
if (face_sets) {
|
||||
for (int i = 0; i < me->totpoly; i++) {
|
||||
unode->face_sets[i] = face_sets[i];
|
||||
}
|
||||
PBVHFaceIter fd;
|
||||
BKE_pbvh_face_iter_begin (ss->pbvh, unode->node, fd) {
|
||||
unode->face_sets[fd.i] = fd.face_set ? *fd.face_set : SCULPT_FACE_SET_NONE;
|
||||
}
|
||||
else {
|
||||
memset(unode->face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * me->totpoly);
|
||||
}
|
||||
|
||||
BLI_addtail(&usculpt->nodes, unode);
|
||||
|
||||
return unode;
|
||||
BKE_pbvh_face_iter_end(fd);
|
||||
}
|
||||
|
||||
static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type)
|
||||
|
@ -1616,11 +1638,6 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
|
|||
BLI_thread_unlock(LOCK_CUSTOM1);
|
||||
return unode;
|
||||
}
|
||||
if (type == SCULPT_UNDO_FACE_SETS) {
|
||||
unode = sculpt_undo_face_sets_push(ob, type);
|
||||
BLI_thread_unlock(LOCK_CUSTOM1);
|
||||
return unode;
|
||||
}
|
||||
if ((unode = SCULPT_undo_get_node(node, type))) {
|
||||
BLI_thread_unlock(LOCK_CUSTOM1);
|
||||
return unode;
|
||||
|
@ -1678,7 +1695,9 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
|
|||
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
|
||||
BLI_assert_msg(0, "Dynamic topology should've already been handled");
|
||||
case SCULPT_UNDO_GEOMETRY:
|
||||
break;
|
||||
case SCULPT_UNDO_FACE_SETS:
|
||||
sculpt_undo_store_face_sets(ss, unode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue