Fix T75743: Implement restore for brushes that modify their own data

This implements the restore function for Draw Face Sets and Layer, which
don't affect coordinates or masks directly. This is needed for the
anchored and dot brush strokes.

Layer frees the current displacement and a new one is created on each
stroke sample. Draw Face Sets copies the data back from the first undo
node to the mesh datalayer.

Also fixes T75727

Reviewed By: jbakker

Maniphest Tasks: T75727

Differential Revision: https://developer.blender.org/D7442
This commit is contained in:
Pablo Dobarro 2020-04-15 20:49:53 +02:00
parent 9d8a583482
commit e6fab27d6a
Notes: blender-bot 2023-02-14 05:28:01 +01:00
Referenced by issue #75743, Crash: Sculpt Layer brush + Stroke Method "Anchored" makes Blender crash
Referenced by issue #75727, using Draw faceset with Anchored doesn't work
4 changed files with 43 additions and 21 deletions

View File

@ -4157,8 +4157,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 &&
ss->cache->first_time) {
if (ss->cache->layer_displacement_factor == NULL) {
ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
"layer displacement factor");
}
@ -5283,6 +5282,23 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
/* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
* vertices and uses regular coords undo. */
/* It also assings the paint_face_set here as it needs to be done regardless of the stroke type
* and the number of nodes under the brush influence. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time &&
ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) {
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);
}
else {
/* By default create a new Face Sets. */
ss->cache->paint_face_set = SCULPT_face_set_next_available_get(ss);
}
}
/* Only act if some verts are inside the brush area. */
if (totnode) {
float location[3];
@ -5298,13 +5314,6 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
/* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
* vertices and uses regular coords undo. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time &&
ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) {
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
}
if (sculpt_brush_needs_normal(ss, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
}
@ -6842,6 +6851,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
/* Restore the mesh before continuing with anchored stroke. */
@ -6851,7 +6861,19 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
brush->sculpt_tool == SCULPT_TOOL_CLOTH) &&
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) {
MEM_SAFE_FREE(ss->cache->layer_displacement_factor);
}
}
}

View File

@ -189,18 +189,6 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0 &&
ss->cache->radial_symmetry_pass == 0) {
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);
}
else {
/* By default create a new Face Sets. */
ss->cache->paint_face_set = SCULPT_face_set_next_available_get(ss);
}
}
BKE_curvemapping_initialize(brush->curve);
/* Threaded loop over nodes. */

View File

@ -856,6 +856,7 @@ void SCULPT_cache_free(StrokeCache *cache);
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
SculptUndoNode *SCULPT_undo_get_first_node();
void SCULPT_undo_push_begin(const char *name);
void SCULPT_undo_push_end(void);
void SCULPT_undo_push_end_ex(const bool use_nested_undo);

View File

@ -892,6 +892,17 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
}
SculptUndoNode *SCULPT_undo_get_first_node()
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
if (usculpt == NULL) {
return NULL;
}
return usculpt->nodes.first;
}
static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode)
{
PBVHNode *node = unode->node;