Sculpt: enable dyntopo on paint brushes

* Paint brushes will now support
  dyntopo if "dyntopo disabled"
  (the one in their brush settings,
   not the global setting in the
   "Dynamic Topology" panel) is unchecked.
* Fixed dyntopo undo not properly handling
  pushing more then one undo type.
This commit is contained in:
Joseph Eagar 2021-10-11 13:27:47 -07:00
parent cbaa9f723b
commit 7293c2b5e5
8 changed files with 87 additions and 33 deletions

View File

@ -364,6 +364,7 @@ void BKE_brush_channelset_apply_mapping(BrushChannelSet *chset, BrushMappingData
void BKE_brush_check_toolsettings(struct Sculpt *sd);
void BKE_brush_channelset_ui_init(struct Brush *brush, int tool);
void BKE_brush_channelset_check_radius(BrushChannelSet *chset);
void BKE_builtin_apply_hard_edge_mode(BrushChannelSet *chset, bool do_apply);
const char *BKE_brush_channel_category_get(BrushChannel *ch);
void BKE_brush_channel_category_set(BrushChannel *ch, const char *str);

View File

@ -1450,6 +1450,31 @@ void BKE_brush_commandset_inherit_all_mappings(BrushChannelSet *chset)
}
}
ATTR_NO_OPT static void commandlist_add_dyntopo(BrushChannelSet *chset,
BrushCommandList *cl,
Brush *brush,
int tool,
bool hard_edge_mode,
float radius_base)
{
if (!BKE_brush_channelset_get_int(chset, "dyntopo_disabled", NULL)) {
BrushCommand *cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true),
SCULPT_TOOL_DYNTOPO);
BKE_builtin_apply_hard_edge_mode(cmd->params, hard_edge_mode);
float spacing = BKE_brush_channelset_get_float(chset, "dyntopo_spacing", NULL);
float radius2 = BKE_brush_channelset_get_float(chset, "dyntopo_radius_scale", NULL);
radius2 *= radius_base;
int_set_uninherit(cmd->params, use_ctrl_invert, false);
float_set_uninherit(cmd->params, spacing, spacing);
float_set_uninherit(cmd->params, radius, radius2);
BKE_brush_commandset_inherit_all_mappings(cmd->params);
}
}
static void bke_builtin_commandlist_create_paint(Brush *brush,
BrushChannelSet *chset,
BrushCommandList *cl,
@ -1460,6 +1485,7 @@ static void bke_builtin_commandlist_create_paint(Brush *brush,
cmd = BKE_brush_commandlist_add(cl, chset, true);
BKE_brush_command_init(cmd, tool);
BKE_brush_commandset_inherit_all_mappings(cmd->params);
float radius = BRUSHSET_GET_FLOAT(chset, radius, NULL);
@ -1496,6 +1522,8 @@ static void bke_builtin_commandlist_create_paint(Brush *brush,
float_set_uninherit(cmd->params, radius, radius * autosmooth_scale);
float_set_uninherit(cmd->params, projection, autosmooth_projection);
float_set_uninherit(cmd->params, spacing, autosmooth_spacing);
BKE_brush_commandset_inherit_all_mappings(cmd->params);
}
float vcol_boundary = BKE_brush_channelset_get_float(chset, "vcol_boundary_factor", NULL);
@ -1508,11 +1536,15 @@ static void bke_builtin_commandlist_create_paint(Brush *brush,
float_set_uninherit(cmd->params, radius, radius * GETF("vcol_boundary_radius_scale"));
float_set_uninherit(cmd->params, spacing, GETF("vcol_boundary_spacing"));
float_set_uninherit(cmd->params, strength, vcol_boundary);
BKE_brush_commandset_inherit_all_mappings(cmd->params);
}
#undef GETF
BKE_brush_commandset_inherit_all_mappings(cmd->params);
bool hard_edge_mode = BRUSHSET_GET_INT(chset, hard_edge_mode, NULL);
commandlist_add_dyntopo(chset, cl, brush, tool, hard_edge_mode, radius);
// float
}
@ -1567,6 +1599,7 @@ void BKE_builtin_commandlist_create(Brush *brush,
cmd = BKE_brush_commandlist_add(cl, chset, true);
BKE_brush_command_init(cmd, tool);
BKE_builtin_apply_hard_edge_mode(cmd->params, hard_edge_mode);
BKE_brush_commandset_inherit_all_mappings(cmd->params);
float radius = BKE_brush_channelset_get_float(chset, "radius", NULL);
@ -1603,6 +1636,7 @@ void BKE_builtin_commandlist_create(Brush *brush,
if (!no_autosmooth && autosmooth > 0.0f) {
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true), SCULPT_TOOL_SMOOTH);
BKE_builtin_apply_hard_edge_mode(cmd->params, hard_edge_mode);
BKE_brush_commandset_inherit_all_mappings(cmd->params);
BrushChannel *ch = BRUSHSET_ENSURE_BUILTIN(cmd->params, falloff_curve);
BrushChannel *ch2 = BRUSHSET_LOOKUP(chset, autosmooth_falloff_curve);
@ -1667,25 +1701,12 @@ void BKE_builtin_commandlist_create(Brush *brush,
float_set_uninherit(cmd->params, radius, radius * topology_rake_scale);
float_set_uninherit(cmd->params, projection, topology_rake_projection);
float_set_uninherit(cmd->params, spacing, topology_rake_spacing);
BKE_brush_commandset_inherit_all_mappings(cmd->params);
}
/* build dyntopo command */
if (!BKE_brush_channelset_get_int(chset, "dyntopo_disabled", NULL)) {
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true), SCULPT_TOOL_DYNTOPO);
BKE_builtin_apply_hard_edge_mode(cmd->params, hard_edge_mode);
float spacing = BKE_brush_channelset_get_float(chset, "dyntopo_spacing", NULL);
float radius2 = BKE_brush_channelset_get_float(chset, "dyntopo_radius_scale", NULL);
radius2 *= radius;
int_set_uninherit(cmd->params, use_ctrl_invert, false);
float_set_uninherit(cmd->params, spacing, spacing);
float_set_uninherit(cmd->params, radius, radius2);
}
BKE_brush_commandset_inherit_all_mappings(cmd->params);
commandlist_add_dyntopo(chset, cl, brush, tool, hard_edge_mode, radius);
}
void BKE_brush_channelset_read_lib(BlendLibReader *reader, ID *id, BrushChannelSet *chset)

View File

@ -1461,6 +1461,9 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
break;
case SCULPT_TOOL_PAINT:
SHOWWRK(color);
SHOWWRK(dyntopo_disabled);
SHOWCTX(dyntopo_disabled);
SHOWWRK(secondary_color);
SHOWWRK(wet_mix);
SHOWWRK(wet_persistence);
@ -1614,6 +1617,7 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
GETCH(slide_deform_type)->ivalue = BRUSH_SLIDE_DEFORM_DRAG;
break;
case SCULPT_TOOL_PAINT:
BRUSHSET_SET_BOOL(chset, dyntopo_disabled, true);
BRUSHSET_SET_FLOAT(chset, hardness, 0.4f);
BRUSHSET_SET_FLOAT(chset, spacing, 10.0f);
BRUSHSET_SET_FLOAT(chset, strength, 0.6f);

View File

@ -1842,6 +1842,11 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (brush->channels && brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
BKE_brush_channelset_ui_init(brush, brush->sculpt_tool);
}
else if (brush->channels &&
ELEM(brush->sculpt_plane, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
BKE_brush_channelset_ui_init(brush, brush->sculpt_tool);
BRUSHSET_SET_BOOL(brush->channels, dyntopo_disabled, true);
}
}
}
/**

View File

@ -930,8 +930,11 @@ typedef struct SculptUndoNode {
/* Sculpt Face Sets */
int *face_sets;
bool *nodemap;
// dyntopo stuff
int *nodemap;
int nodemap_size;
int typemask;
size_t undo_size;
// int gen, lasthash;

View File

@ -121,13 +121,13 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
const float bstrength = fabsf(ss->cache->bstrength);
PBVHVertexIter vd;
PBVHColorBufferNode *color_buffer;
// PBVHColorBufferNode *color_buffer;
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
orig_data.datatype = SCULPT_UNDO_COLOR;
color_buffer = BKE_pbvh_node_color_buffer_get(data->nodes[n]);
// color_buffer = BKE_pbvh_node_color_buffer_get(data->nodes[n]);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
@ -187,16 +187,19 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
float wet_mix_color[4];
float buffer_color[4];
MSculptVert *mv = SCULPT_vertex_get_mdyntopo(ss, vd.vertex);
float *color_buffer = mv->origcolor;
mul_v4_v4fl(paint_color, brush_color, fade * ss->cache->paint_brush.flow);
mul_v4_v4fl(wet_mix_color, data->wet_mix_sampled_color, fade * ss->cache->paint_brush.flow);
/* Interpolate with the wet_mix color for wet paint mixing. */
blend_color_interpolate_float(
paint_color, paint_color, wet_mix_color, ss->cache->paint_brush.wet_mix);
blend_color_mix_float(color_buffer->color[vd.i], color_buffer->color[vd.i], paint_color);
blend_color_mix_float(color_buffer, color_buffer, paint_color);
/* Final mix over the original color using brush alpha. */
mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], alpha);
mul_v4_v4fl(buffer_color, color_buffer, alpha);
IMB_blend_color_float(vd.col, orig_data.col, buffer_color, brush->blend);
@ -421,7 +424,9 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
float current_disp[3];
float current_disp_norm[3];
float interp_color[4];
copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]);
float *prev_color = (float *)SCULPT_temp_cdata_get(vd.vertex, data->scl);
copy_v4_v4(interp_color, prev_color);
switch (brush->smear_deform_type) {
case BRUSH_SMEAR_DEFORM_DRAG:
@ -442,7 +447,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
float vertex_disp[3];
float vertex_disp_norm[3];
sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co);
const float *neighbor_color = ss->cache->prev_colors[ni.index];
const float *neighbor_color = SCULPT_temp_cdata_get(ni.vertex, data->scl);
normalize_v3_v3(vertex_disp_norm, vertex_disp);
if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
continue;
@ -456,8 +461,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
blend_color_interpolate_float(
vd.col, ss->cache->prev_colors[vd.index], interp_color, fade * blend);
blend_color_interpolate_float(vd.col, prev_color, interp_color, fade * blend);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@ -475,7 +479,10 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.vertex));
copy_v4_v4((float *)SCULPT_temp_cdata_get(vd.vertex, data->scl),
SCULPT_vertex_color_get(ss, vd.vertex));
// copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.vertex));
}
BKE_pbvh_vertex_iter_end;
}
@ -489,6 +496,12 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
return;
}
SculptCustomLayer prev_scl;
SculptLayerParams params = {.permanent = false, .simple_array = false};
SCULPT_temp_customlayer_ensure(ss, ATTR_DOMAIN_POINT, CD_PROP_COLOR, "smear_previous", &params);
SCULPT_temp_customlayer_get(
ss, ATTR_DOMAIN_POINT, CD_PROP_COLOR, "smear_previous", &prev_scl, &params);
SCULPT_vertex_random_access_ensure(ss);
const int totvert = SCULPT_vertex_count_get(ss);
@ -509,6 +522,7 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.scl = &prev_scl,
.brush = brush,
.nodes = nodes,
};

View File

@ -1927,17 +1927,24 @@ bool SCULPT_ensure_dyntopo_node_undo(Object *ob,
UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode = usculpt->nodes.first;
if (!unode || unode->type != type) {
if (!unode) {
unode = sculpt_undo_alloc_node_type(ob, type);
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
unode->type = type;
unode->typemask = 1 << type;
unode->applied = true;
unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
return SCULPT_ensure_dyntopo_node_undo(ob, node, type, extraType);
}
else if (!(unode->typemask & (1 << type))) {
unode->typemask |= 1 << type;
/* add a log sub-entry */
BM_log_entry_add_ex(ss->bm, ss->bm_log, true);
}
if (!node) {
return false;
@ -1946,7 +1953,8 @@ bool SCULPT_ensure_dyntopo_node_undo(Object *ob,
int n = BKE_pbvh_get_node_id(ss->pbvh, node);
if (unode->nodemap_size <= n) {
int newsize = (n + 1) * 2;
int newsize = (n + 1);
newsize += newsize >> 1;
if (!unode->nodemap) {
unode->nodemap = MEM_callocN(sizeof(*unode->nodemap) * newsize, "unode->nodemap");
@ -1958,11 +1966,11 @@ bool SCULPT_ensure_dyntopo_node_undo(Object *ob,
unode->nodemap_size = newsize;
}
if (unode->nodemap[n]) {
if (unode->nodemap[n] & (1 << type)) {
return false;
}
unode->nodemap[n] = 1;
unode->nodemap[n] |= 1 << type;
sculpt_undo_bmesh_push(ob, node, type);
if (extraType >= 0) {

View File

@ -551,8 +551,6 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_BOUNDARY, \
SCULPT_TOOL_POSE, \
SCULPT_TOOL_DRAW_FACE_SETS, \
SCULPT_TOOL_PAINT, \
SCULPT_TOOL_SMEAR, \
\
/* These brushes could handle dynamic topology, \ \
* but user feedback indicates it's better not to */ \