Sculpt: fix drag-dot/anchored for face sets

* Added an API for original face sets
  based on the SculptCustomLayer API.
This commit is contained in:
Joseph Eagar 2021-09-30 01:36:08 -07:00
parent f6da6961e0
commit 9c30155c47
5 changed files with 131 additions and 21 deletions

View File

@ -567,6 +567,7 @@ enum {
SCULPT_SCL_PERS_DISP,
SCULPT_SCL_LAYER_DISP,
SCULPT_SCL_LAYER_STROKE_ID,
SCULPT_SCL_ORIG_FSETS,
SCULPT_SCL_LAYER_MAX
};

View File

@ -38,6 +38,17 @@ extern "C" {
// experimental feature to detect quad diagonals and mark (but not dissolve) them
//#define SCULPT_DIAGONAL_EDGE_MARKS
/*
These structs represent logical verts/edges/faces.
for PBVH_GRIDS and PBVH_FACES they store integer
offsets, PBVH_BMESH stores pointers.
The idea is to enforce stronger type checking by encapsulating
intptr_t's in structs.*/
typedef struct SculptElemRef {
intptr_t i;
} SculptElemRef;
typedef struct SculptVertRef {
intptr_t i;
} SculptVertRef;

View File

@ -2959,11 +2959,18 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
SCULPT_orig_vert_data_unode_init(&orig_data, data->ob, unode);
bool modified = false;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
if (len_squared_v3v3(vd.co, orig_data.co) > FLT_EPSILON) {
modified = true;
}
copy_v3_v3(vd.co, orig_data.co);
if (vd.no) {
copy_v3_v3_short(vd.no, orig_data.no);
}
@ -2972,9 +2979,17 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
}
}
else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
if ((*vd.mask - orig_data.mask) * (*vd.mask - orig_data.mask) > FLT_EPSILON) {
modified = true;
}
*vd.mask = orig_data.mask;
}
else if (orig_data.unode->type == SCULPT_UNDO_COLOR && vd.col && orig_data.col) {
if (len_squared_v4v4(vd.col, orig_data.col) > FLT_EPSILON) {
modified = true;
}
copy_v4_v4(vd.col, orig_data.col);
}
@ -2984,7 +2999,9 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_update(data->nodes[n]);
if (modified) {
BKE_pbvh_node_mark_update(data->nodes[n]);
}
}
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
@ -2997,11 +3014,6 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
/**
* Disable multi-threading when dynamic-topology is enabled. Otherwise,
* new entries might be inserted by #SCULPT_undo_push_node() into the #GHash
* used internally by #BM_log_original_vert_co() by a different thread. See T33787.
*/
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
@ -3010,7 +3022,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true && !ss->bm, totnode);
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
BKE_pbvh_node_color_buffer_free(ss->pbvh);
@ -3784,10 +3796,10 @@ static void calc_area_normal_and_center(
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor.
*/
ATTR_NO_OPT static float brush_strength(const Sculpt *sd,
const StrokeCache *cache,
const float feather,
const UnifiedPaintSettings *ups)
static float brush_strength(const Sculpt *sd,
const StrokeCache *cache,
const float feather,
const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
const Brush *brush = cache->brush; // BKE_paint_brush((Paint *)&sd->paint);
@ -8784,8 +8796,20 @@ void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
* Check that original data is for anchored and drag dot modes
*/
if (brush->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT)) {
if (SCULPT_stroke_is_first_brush_step(ss->cache) &&
brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) {
SCULPT_face_ensure_original(ss);
for (int i = 0; i < ss->totfaces; i++) {
SculptFaceRef face = BKE_pbvh_table_index_to_face(ss->pbvh, i);
SCULPT_face_check_origdata(ss, face);
}
}
for (int i = 0; i < totnode; i++) {
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[i], vd, PBVH_ITER_UNIQUE) {
SCULPT_vertex_check_origdata(ss, vd.vertex);
}
@ -11421,13 +11445,11 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
BKE_brush_use_size_pressure(brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
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];
}
}
for (int i = 0; i < ss->totfaces; i++) {
SculptFaceRef face = BKE_pbvh_table_index_to_face(ss->pbvh, i);
int origf = SCULPT_face_set_original_get(ss, face);
SCULPT_face_set_set(ss, face, origf);
}
paint_mesh_restore_co(sd, ob);

View File

@ -127,6 +127,57 @@ int SCULPT_face_set_set(SculptSession *ss, SculptFaceRef face, int fset)
return ret;
}
const char orig_faceset_attr_name[] = "_sculpt_original_fsets";
void SCULPT_face_check_origdata(SculptSession *ss, SculptFaceRef face)
{
if (!ss->custom_layers[SCULPT_SCL_ORIG_FSETS]) {
return;
}
short *s = (short *)SCULPT_temp_cdata_get_f(face, ss->custom_layers[SCULPT_SCL_ORIG_FSETS]);
// pack ss->stroke_id in higher 16 bits
if (s[1] != ss->stroke_id) {
s[0] = SCULPT_face_set_get(ss, face);
s[1] = ss->stroke_id;
}
}
int SCULPT_face_set_original_get(SculptSession *ss, SculptFaceRef face)
{
if (!ss->custom_layers[SCULPT_SCL_ORIG_FSETS]) {
return SCULPT_face_set_get(ss, face);
}
short *s = (short *)SCULPT_temp_cdata_get_f(face, ss->custom_layers[SCULPT_SCL_ORIG_FSETS]);
if (s[1] != ss->stroke_id) {
s[0] = SCULPT_face_set_get(ss, face);
s[1] = ss->stroke_id;
}
return s[0];
}
void SCULPT_face_ensure_original(SculptSession *ss)
{
if (ss->custom_layers[SCULPT_SCL_ORIG_FSETS]) {
return;
}
SculptCustomLayer *scl = MEM_callocN(sizeof(*scl), "orig fset scl");
SCULPT_temp_customlayer_get(ss,
ATTR_DOMAIN_FACE,
CD_PROP_INT32,
"orig_faceset_attr_name",
scl,
&((SculptLayerParams){.permanent = false, .simple_array = false}));
ss->custom_layers[SCULPT_SCL_ORIG_FSETS] = scl;
}
int SCULPT_face_set_flag_get(SculptSession *ss, SculptFaceRef face, char flag)
{
if (ss->bm) {

View File

@ -336,6 +336,10 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, SculptVertRef ind
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
void SCULPT_face_ensure_original(SculptSession *ss);
int SCULPT_face_set_original_get(SculptSession *ss, SculptFaceRef face);
void SCULPT_face_check_origdata(SculptSession *ss, SculptFaceRef face);
int SCULPT_face_set_get(SculptSession *ss, SculptFaceRef face);
// returns previous face set
@ -1800,7 +1804,6 @@ int SCULPT_get_symmetry_pass(const SculptSession *ss);
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
void SCULPT_reorder_bmesh(SculptSession *ss);
// TODO: support faces
static inline void *SCULPT_temp_cdata_get(SculptVertRef vertex, SculptCustomLayer *scl)
{
if (scl->data) {
@ -1808,14 +1811,36 @@ static inline void *SCULPT_temp_cdata_get(SculptVertRef vertex, SculptCustomLaye
int idx = (int)vertex.i;
if (scl->from_bmesh) {
BMVert *v = (BMVert *)vertex.i;
BMElem *v = (BMElem *)vertex.i;
idx = v->head.index;
}
return p + scl->elemsize * (int)vertex.i;
}
else {
BMVert *v = (BMVert *)vertex.i;
BMElem *v = (BMElem *)vertex.i;
return BM_ELEM_CD_GET_VOID_P(v, scl->cd_offset);
}
return NULL;
}
// arg, duplicate functions!
static inline void *SCULPT_temp_cdata_get_f(SculptFaceRef vertex, SculptCustomLayer *scl)
{
if (scl->data) {
char *p = (char *)scl->data;
int idx = (int)vertex.i;
if (scl->from_bmesh) {
BMElem *v = (BMElem *)vertex.i;
idx = v->head.index;
}
return p + scl->elemsize * (int)vertex.i;
}
else {
BMElem *v = (BMElem *)vertex.i;
return BM_ELEM_CD_GET_VOID_P(v, scl->cd_offset);
}