Cleanup: Sculpt: Various non-functional sculpt_ops.cc changes

* Move grab brush preview method to `grab.cc`
* Use `enum class` where possible
* Use `const` where possible
* Use C++ math libraries where possible
  * float3 instead of float *
  * numeric limits & constexpr instead of macros
* Clarify naming of some variables
* Add doxygen sections

Pull Request: https://projects.blender.org/blender/blender/pulls/127743
This commit is contained in:
Sean Kim
2024-09-17 19:20:23 +02:00
committed by Sean Kim
parent 7acdb8f90d
commit b70c00bf4e
4 changed files with 253 additions and 222 deletions

View File

@@ -266,4 +266,70 @@ void do_grab_brush(const Depsgraph &depsgraph,
bke::pbvh::flush_bounds_to_parents(pbvh);
}
void geometry_preview_lines_update(Depsgraph &depsgraph,
Object &object,
SculptSession &ss,
float radius)
{
ss.preview_verts = {};
/* This function is called from the cursor drawing code, so the tree may not be built yet. */
const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(object);
if (!pbvh) {
return;
}
if (!ss.deform_modifiers_active) {
return;
}
if (pbvh->type() != bke::pbvh::Type::Mesh) {
return;
}
BKE_sculpt_update_object_for_edit(&depsgraph, &object, false);
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
/* Always grab active shape key if the sculpt happens on shapekey. */
const Span<float3> positions = ss.shapekey_active ?
bke::pbvh::vert_positions_eval(depsgraph, object) :
mesh.vert_positions();
const OffsetIndices faces = mesh.faces();
const Span<int> corner_verts = mesh.corner_verts();
const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
const bke::AttributeAccessor attributes = mesh.attributes();
const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
const int active_vert = std::get<int>(ss.active_vert());
const float3 brush_co = positions[active_vert];
const float radius_sq = radius * radius;
Vector<int> preview_verts;
Vector<int> neighbors;
BitVector<> visited_verts(positions.size());
std::queue<int> queue;
queue.push(active_vert);
while (!queue.empty()) {
const int from_vert = queue.front();
queue.pop();
neighbors.clear();
for (const int neighbor : vert_neighbors_get_mesh(
faces, corner_verts, vert_to_face_map, hide_poly, from_vert, neighbors))
{
preview_verts.append(from_vert);
preview_verts.append(neighbor);
if (visited_verts[neighbor]) {
continue;
}
visited_verts[neighbor].set();
if (math::distance_squared(brush_co, positions[neighbor]) < radius_sq) {
queue.push(neighbor);
}
}
}
ss.preview_verts = preview_verts.as_span();
}
} // namespace blender::ed::sculpt_paint

View File

@@ -1874,7 +1874,8 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_GRAB &&
(brush.flag & BRUSH_GRAB_ACTIVE_VERTEX))
{
geometry_preview_lines_update(pcontext->C, *pcontext->ss, pcontext->radius);
geometry_preview_lines_update(
*pcontext->depsgraph, *pcontext->vc.obact, *pcontext->ss, pcontext->radius);
sculpt_geometry_preview_lines_draw(
*pcontext->depsgraph, pcontext->pos, *pcontext->brush, active_object);
}

View File

@@ -424,7 +424,10 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
namespace blender::ed::sculpt_paint {
void geometry_preview_lines_update(bContext *C, SculptSession &ss, float radius);
void geometry_preview_lines_update(Depsgraph &depsgraph,
Object &object,
SculptSession &ss,
float radius);
}

View File

@@ -81,7 +81,11 @@
namespace blender::ed::sculpt_paint {
static int sculpt_set_persistent_base_exec(bContext *C, wmOperator * /*op*/)
/* -------------------------------------------------------------------- */
/** \name Set Persistent Base Operator
* \{ */
static int set_persistent_base_exec(bContext *C, wmOperator * /*op*/)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object &ob = *CTX_data_active_object(C);
@@ -137,15 +141,19 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
ot->idname = "SCULPT_OT_set_persistent_base";
ot->description = "Reset the copy of the mesh that is being sculpted on";
ot->exec = sculpt_set_persistent_base_exec;
ot->exec = set_persistent_base_exec;
ot->poll = SCULPT_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************* SCULPT_OT_optimize *************************/
/** \} */
static int sculpt_optimize_exec(bContext *C, wmOperator * /*op*/)
/* -------------------------------------------------------------------- */
/** \name Optimize Operator
* \{ */
static int optimize_exec(bContext *C, wmOperator * /*op*/)
{
Object &ob = *CTX_data_active_object(C);
@@ -167,15 +175,19 @@ static void SCULPT_OT_optimize(wmOperatorType *ot)
ot->idname = "SCULPT_OT_optimize";
ot->description = "Recalculate the sculpt BVH to improve performance";
ot->exec = sculpt_optimize_exec;
ot->exec = optimize_exec;
ot->poll = SCULPT_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************* Dynamic topology symmetrize ********************/
/** \} */
static bool sculpt_no_multires_poll(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Symmetrize Operator
* \{ */
static bool no_multires_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (!ob) {
@@ -191,7 +203,7 @@ static bool sculpt_no_multires_poll(bContext *C)
return false;
}
static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
static int symmetrize_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
@@ -276,25 +288,29 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
ot->idname = "SCULPT_OT_symmetrize";
ot->description = "Symmetrize the topology modifications";
ot->exec = sculpt_symmetrize_exec;
ot->poll = sculpt_no_multires_poll;
ot->exec = symmetrize_exec;
ot->poll = no_multires_poll;
PropertyRNA *prop = RNA_def_float(ot->srna,
"merge_tolerance",
0.0005f,
0.0f,
FLT_MAX,
std::numeric_limits<float>::max(),
"Merge Distance",
"Distance within which symmetrical vertices are merged",
0.0f,
1.0f);
RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 0.001, 5);
RNA_def_property_ui_range(prop, 0.0, std::numeric_limits<float>::max(), 0.001, 5);
}
/**** Toggle operator for turning sculpt mode on or off ****/
/** \} */
static void sculpt_init_session(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
/* -------------------------------------------------------------------- */
/** \name Sculpt Mode Toggle Operator
* \{ */
static void init_sculpt_mode_session(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
{
/* Create persistent sculpt mode data. */
BKE_sculpt_toolsettings_data_ensure(&bmain, &scene);
@@ -375,7 +391,7 @@ void object_sculpt_mode_enter(Main &bmain,
/* Enter sculpt mode. */
ob.mode |= mode_flag;
sculpt_init_session(bmain, depsgraph, scene, ob);
init_sculpt_mode_session(bmain, depsgraph, scene, ob);
if (!(fabsf(ob.scale[0] - ob.scale[1]) < 1e-4f && fabsf(ob.scale[1] - ob.scale[2]) < 1e-4f)) {
BKE_report(
@@ -403,7 +419,7 @@ void object_sculpt_mode_enter(Main &bmain,
message_unsupported = RPT_("multi-res modifier");
}
else {
dyntopo::WarnFlag flag = dyntopo::check_attribute_warning(scene, ob);
const dyntopo::WarnFlag flag = dyntopo::check_attribute_warning(scene, ob);
if (flag == 0) {
/* pass */
}
@@ -420,14 +436,14 @@ void object_sculpt_mode_enter(Main &bmain,
message_unsupported = RPT_("constructive modifier");
}
else {
BLI_assert(0);
BLI_assert_unreachable();
}
}
if ((message_unsupported == nullptr) || force_dyntopo) {
/* Needed because we may be entering this mode before the undo system loads. */
wmWindowManager *wm = static_cast<wmWindowManager *>(bmain.wm.first);
bool has_undo = wm->undo_stack != nullptr;
const bool has_undo = wm->undo_stack != nullptr;
/* Undo push is needed to prevent memory leak. */
if (has_undo) {
undo::push_begin_ex(ob, "Dynamic topology enable");
@@ -581,73 +597,13 @@ static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
void geometry_preview_lines_update(bContext *C, SculptSession &ss, float radius)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
/** \} */
ss.preview_verts = {};
/* -------------------------------------------------------------------- */
/** \name Sample Color Operator
* \{ */
/* This function is called from the cursor drawing code, so the tree may not be build yet. */
const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(*ob);
if (!pbvh) {
return;
}
if (!ss.deform_modifiers_active) {
return;
}
if (pbvh->type() != bke::pbvh::Type::Mesh) {
return;
}
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
/* Always grab active shape key if the sculpt happens on shapekey. */
const Span<float3> positions = ss.shapekey_active ?
bke::pbvh::vert_positions_eval(*depsgraph, *ob) :
mesh.vert_positions();
const OffsetIndices faces = mesh.faces();
const Span<int> corner_verts = mesh.corner_verts();
const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
const bke::AttributeAccessor attributes = mesh.attributes();
const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
const int active_vert = std::get<int>(ss.active_vert());
const float3 brush_co = positions[active_vert];
const float radius_sq = radius * radius;
Vector<int> preview_verts;
Vector<int> neighbors;
BitVector<> visited_verts(positions.size());
std::queue<int> queue;
queue.push(active_vert);
while (!queue.empty()) {
const int from_vert = queue.front();
queue.pop();
neighbors.clear();
for (const int neighbor : vert_neighbors_get_mesh(
faces, corner_verts, vert_to_face_map, hide_poly, from_vert, neighbors))
{
preview_verts.append(from_vert);
preview_verts.append(neighbor);
if (visited_verts[neighbor]) {
continue;
}
visited_verts[neighbor].set();
if (math::distance_squared(brush_co, positions[neighbor]) < radius_sq) {
queue.push(neighbor);
}
}
}
ss.preview_verts = preview_verts.as_span();
}
static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
Scene &scene = *CTX_data_scene(C);
@@ -702,14 +658,20 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
ot->idname = "SCULPT_OT_sample_color";
ot->description = "Sample the vertex color of the active vertex";
ot->invoke = sculpt_sample_color_invoke;
ot->invoke = sample_color_invoke;
ot->poll = SCULPT_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_DEPENDS_ON_CURSOR;
}
/** \} */
namespace mask {
/* -------------------------------------------------------------------- */
/** \name Mask By Color
* \{ */
/**
* #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
* mask based on the difference between two colors (the active color and the color of any other
@@ -721,14 +683,14 @@ namespace mask {
*/
#define MASK_BY_COLOR_SLOPE 0.25f
static float sculpt_mask_by_color_delta_get(const float *color_a,
const float *color_b,
const float threshold,
const bool invert)
static float color_delta_get(const float3 &color_a,
const float3 &color_b,
const float threshold,
const bool invert)
{
float len = len_v3v3(color_a, color_b);
float len = math::distance(color_a, color_b);
/* Normalize len to the (0, 1) range. */
len = len / M_SQRT3;
len = len / math::numbers::sqrt3_v<float>;
if (len < threshold - MASK_BY_COLOR_SLOPE) {
len = 1.0f;
@@ -746,26 +708,26 @@ static float sculpt_mask_by_color_delta_get(const float *color_a,
return len;
}
static float sculpt_mask_by_color_final_mask_get(const float current_mask,
const float new_mask,
const bool invert,
const bool preserve_mask)
static float final_mask_get(const float current_mask,
const float new_mask,
const bool invert,
const bool preserve_mask)
{
if (preserve_mask) {
if (invert) {
return min_ff(current_mask, new_mask);
return std::min(current_mask, new_mask);
}
return max_ff(current_mask, new_mask);
return std::max(current_mask, new_mask);
}
return new_mask;
}
static void sculpt_mask_by_color_contiguous_mesh(const Depsgraph &depsgraph,
Object &object,
const int vert,
const float threshold,
const bool invert,
const bool preserve_mask)
static void mask_by_color_contiguous_mesh(const Depsgraph &depsgraph,
Object &object,
const int vert,
const float threshold,
const bool invert,
const bool preserve_mask)
{
const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
@@ -783,12 +745,12 @@ static void sculpt_mask_by_color_contiguous_mesh(const Depsgraph &depsgraph,
flood.execute(object, vert_to_face_map, [&](int /*from_v*/, int to_v) {
const float4 current_color = float4(colors[to_v]);
float new_vertex_mask = sculpt_mask_by_color_delta_get(
current_color, active_color, threshold, invert);
float new_vertex_mask = color_delta_get(
current_color.xyz(), active_color.xyz(), threshold, invert);
new_mask[to_v] = new_vertex_mask;
float len = len_v3v3(current_color, active_color);
len = len / M_SQRT3;
float len = math::distance(current_color.xyz(), active_color.xyz());
len = len / math::numbers::sqrt3_v<float>;
return len <= threshold;
});
@@ -796,20 +758,19 @@ static void sculpt_mask_by_color_contiguous_mesh(const Depsgraph &depsgraph,
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
update_mask_mesh(
depsgraph, object, node_mask, [&](MutableSpan<float> node_mask, const Span<int> verts) {
depsgraph, object, node_mask, [&](MutableSpan<float> node_masks, const Span<int> verts) {
for (const int i : verts.index_range()) {
node_mask[i] = sculpt_mask_by_color_final_mask_get(
node_mask[i], new_mask[verts[i]], invert, preserve_mask);
node_masks[i] = final_mask_get(node_masks[i], new_mask[verts[i]], invert, preserve_mask);
}
});
}
static void sculpt_mask_by_color_full_mesh(const Depsgraph &depsgraph,
Object &object,
const int vert,
const float threshold,
const bool invert,
const bool preserve_mask)
static void mask_by_color_full_mesh(const Depsgraph &depsgraph,
Object &object,
const int vert,
const float threshold,
const bool invert,
const bool preserve_mask)
{
const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
@@ -822,18 +783,18 @@ static void sculpt_mask_by_color_full_mesh(const Depsgraph &depsgraph,
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
update_mask_mesh(
depsgraph, object, node_mask, [&](MutableSpan<float> node_mask, const Span<int> verts) {
depsgraph, object, node_mask, [&](MutableSpan<float> node_masks, const Span<int> verts) {
for (const int i : verts.index_range()) {
const float current_mask = node_mask[i];
const float new_mask = sculpt_mask_by_color_delta_get(
active_color, colors[verts[i]], threshold, invert);
node_mask[i] = sculpt_mask_by_color_final_mask_get(
current_mask, new_mask, invert, preserve_mask);
const float4 current_color = float4(colors[verts[i]]);
const float current_mask = node_masks[i];
const float new_mask = color_delta_get(
active_color.xyz(), current_color.xyz(), threshold, invert);
node_masks[i] = final_mask_get(current_mask, new_mask, invert, preserve_mask);
}
});
}
static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object &ob = *CTX_data_active_object(C);
@@ -873,11 +834,10 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
const int active_vert = std::get<int>(ss.active_vert());
if (RNA_boolean_get(op->ptr, "contiguous")) {
sculpt_mask_by_color_contiguous_mesh(
*depsgraph, ob, active_vert, threshold, invert, preserve_mask);
mask_by_color_contiguous_mesh(*depsgraph, ob, active_vert, threshold, invert, preserve_mask);
}
else {
sculpt_mask_by_color_full_mesh(*depsgraph, ob, active_vert, threshold, invert, preserve_mask);
mask_by_color_full_mesh(*depsgraph, ob, active_vert, threshold, invert, preserve_mask);
}
undo::push_end(ob);
@@ -894,7 +854,7 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
ot->idname = "SCULPT_OT_mask_by_color";
ot->description = "Creates a mask based on the active color attribute";
ot->invoke = sculpt_mask_by_color_invoke;
ot->invoke = mask_by_color_invoke;
ot->poll = SCULPT_mode_poll;
ot->flag = OPTYPE_REGISTER;
@@ -921,19 +881,21 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
1.0f);
}
enum CavityBakeMixMode {
AUTOMASK_BAKE_MIX,
AUTOMASK_BAKE_MULTIPLY,
AUTOMASK_BAKE_DIVIDE,
AUTOMASK_BAKE_ADD,
AUTOMASK_BAKE_SUBTRACT,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mask from Cavity
* \{ */
enum class ApplyMaskMode : int8_t {
Mix,
Multiply,
Divide,
Add,
Subtract,
};
enum CavityBakeSettingsSource {
AUTOMASK_SETTINGS_OPERATOR,
AUTOMASK_SETTINGS_SCENE,
AUTOMASK_SETTINGS_BRUSH
};
enum class MaskSettingsSource : int8_t { Operator, Scene, Brush };
struct LocalData {
Vector<float> mask;
@@ -941,29 +903,29 @@ struct LocalData {
Vector<float> new_mask;
};
static void calc_new_masks(const CavityBakeMixMode mode,
static void calc_new_masks(const ApplyMaskMode mode,
const Span<float> node_mask,
const MutableSpan<float> new_mask)
{
switch (mode) {
case AUTOMASK_BAKE_MIX:
case ApplyMaskMode::Mix:
break;
case AUTOMASK_BAKE_MULTIPLY:
case ApplyMaskMode::Multiply:
for (const int i : node_mask.index_range()) {
new_mask[i] = node_mask[i] * new_mask[i];
}
break;
case AUTOMASK_BAKE_DIVIDE:
case ApplyMaskMode::Divide:
for (const int i : node_mask.index_range()) {
new_mask[i] = new_mask[i] > 0.00001f ? node_mask[i] / new_mask[i] : 0.0f;
}
break;
case AUTOMASK_BAKE_ADD:
case ApplyMaskMode::Add:
for (const int i : node_mask.index_range()) {
new_mask[i] = node_mask[i] + new_mask[i];
}
break;
case AUTOMASK_BAKE_SUBTRACT:
case ApplyMaskMode::Subtract:
for (const int i : node_mask.index_range()) {
new_mask[i] = node_mask[i] - new_mask[i];
}
@@ -972,14 +934,14 @@ static void calc_new_masks(const CavityBakeMixMode mode,
mask::clamp_mask(new_mask);
}
static void bake_mask_mesh(const Depsgraph &depsgraph,
const Object &object,
const auto_mask::Cache &automasking,
const CavityBakeMixMode mode,
const float factor,
const bke::pbvh::MeshNode &node,
LocalData &tls,
const MutableSpan<float> mask)
static void apply_mask_mesh(const Depsgraph &depsgraph,
const Object &object,
const auto_mask::Cache &automasking,
const ApplyMaskMode mode,
const float factor,
const bke::pbvh::MeshNode &node,
LocalData &tls,
const MutableSpan<float> mask)
{
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
const Span<int> verts = node.verts();
@@ -1004,13 +966,13 @@ static void bake_mask_mesh(const Depsgraph &depsgraph,
scatter_data_mesh(node_mask.as_span(), verts, mask);
}
static void bake_mask_grids(const Depsgraph &depsgraph,
Object &object,
const auto_mask::Cache &automasking,
const CavityBakeMixMode mode,
const float factor,
const bke::pbvh::GridsNode &node,
LocalData &tls)
static void apply_mask_grids(const Depsgraph &depsgraph,
Object &object,
const auto_mask::Cache &automasking,
const ApplyMaskMode mode,
const float factor,
const bke::pbvh::GridsNode &node,
LocalData &tls)
{
SculptSession &ss = *object.sculpt;
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
@@ -1039,13 +1001,13 @@ static void bake_mask_grids(const Depsgraph &depsgraph,
scatter_mask_grids(node_mask.as_span(), subdiv_ccg, grids);
}
static void bake_mask_bmesh(const Depsgraph &depsgraph,
Object &object,
const auto_mask::Cache &automasking,
const CavityBakeMixMode mode,
const float factor,
bke::pbvh::BMeshNode &node,
LocalData &tls)
static void apply_mask_bmesh(const Depsgraph &depsgraph,
Object &object,
const auto_mask::Cache &automasking,
const ApplyMaskMode mode,
const float factor,
bke::pbvh::BMeshNode &node,
LocalData &tls)
{
const SculptSession &ss = *object.sculpt;
const Set<BMVert *, 0> &verts = BKE_pbvh_bmesh_node_unique_verts(&node);
@@ -1070,7 +1032,7 @@ static void bake_mask_bmesh(const Depsgraph &depsgraph,
scatter_mask_bmesh(node_mask.as_span(), *ss.bm, verts);
}
static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
static int mask_from_cavity_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object &ob = *CTX_data_active_object(C);
@@ -1091,8 +1053,8 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
undo::push_begin(ob, op);
CavityBakeMixMode mode = CavityBakeMixMode(RNA_enum_get(op->ptr, "mix_mode"));
float factor = RNA_float_get(op->ptr, "mix_factor");
const ApplyMaskMode mode = ApplyMaskMode(RNA_enum_get(op->ptr, "mix_mode"));
const float factor = RNA_float_get(op->ptr, "mix_factor");
bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
@@ -1100,67 +1062,68 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
/* Set up automasking settings. */
Sculpt sd2 = sd;
Sculpt scene_copy = sd;
CavityBakeSettingsSource src = (CavityBakeSettingsSource)RNA_enum_get(op->ptr,
"settings_source");
MaskSettingsSource src = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
switch (src) {
case AUTOMASK_SETTINGS_OPERATOR:
case MaskSettingsSource::Operator:
if (RNA_boolean_get(op->ptr, "invert")) {
sd2.automasking_flags = BRUSH_AUTOMASKING_CAVITY_INVERTED;
scene_copy.automasking_flags = BRUSH_AUTOMASKING_CAVITY_INVERTED;
}
else {
sd2.automasking_flags = BRUSH_AUTOMASKING_CAVITY_NORMAL;
scene_copy.automasking_flags = BRUSH_AUTOMASKING_CAVITY_NORMAL;
}
if (RNA_boolean_get(op->ptr, "use_curve")) {
sd2.automasking_flags |= BRUSH_AUTOMASKING_CAVITY_USE_CURVE;
scene_copy.automasking_flags |= BRUSH_AUTOMASKING_CAVITY_USE_CURVE;
}
sd2.automasking_cavity_blur_steps = RNA_int_get(op->ptr, "blur_steps");
sd2.automasking_cavity_factor = RNA_float_get(op->ptr, "factor");
scene_copy.automasking_cavity_blur_steps = RNA_int_get(op->ptr, "blur_steps");
scene_copy.automasking_cavity_factor = RNA_float_get(op->ptr, "factor");
sd2.automasking_cavity_curve = sd.automasking_cavity_curve_op;
scene_copy.automasking_cavity_curve = sd.automasking_cavity_curve_op;
break;
case AUTOMASK_SETTINGS_BRUSH:
case MaskSettingsSource::Brush:
if (brush) {
sd2.automasking_flags = brush->automasking_flags;
sd2.automasking_cavity_factor = brush->automasking_cavity_factor;
sd2.automasking_cavity_curve = brush->automasking_cavity_curve;
sd2.automasking_cavity_blur_steps = brush->automasking_cavity_blur_steps;
scene_copy.automasking_flags = brush->automasking_flags;
scene_copy.automasking_cavity_factor = brush->automasking_cavity_factor;
scene_copy.automasking_cavity_curve = brush->automasking_cavity_curve;
scene_copy.automasking_cavity_blur_steps = brush->automasking_cavity_blur_steps;
/* Ensure only cavity masking is enabled. */
sd2.automasking_flags &= BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_CAVITY_USE_CURVE;
scene_copy.automasking_flags &= BRUSH_AUTOMASKING_CAVITY_ALL |
BRUSH_AUTOMASKING_CAVITY_USE_CURVE;
}
else {
sd2.automasking_flags = 0;
scene_copy.automasking_flags = 0;
BKE_report(op->reports, RPT_WARNING, "No active brush");
return OPERATOR_CANCELLED;
}
break;
case AUTOMASK_SETTINGS_SCENE:
case MaskSettingsSource::Scene:
/* Ensure only cavity masking is enabled. */
sd2.automasking_flags &= BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_CAVITY_USE_CURVE;
scene_copy.automasking_flags &= BRUSH_AUTOMASKING_CAVITY_ALL |
BRUSH_AUTOMASKING_CAVITY_USE_CURVE;
break;
}
/* Ensure cavity mask is actually enabled. */
if (!(sd2.automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) {
sd2.automasking_flags |= BRUSH_AUTOMASKING_CAVITY_NORMAL;
if (!(scene_copy.automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) {
scene_copy.automasking_flags |= BRUSH_AUTOMASKING_CAVITY_NORMAL;
}
/* Create copy of brush with cleared automasking settings. */
Brush brush2 = dna::shallow_copy(*brush);
Brush brush_copy = dna::shallow_copy(*brush);
/* Set a brush type that doesn't change topology so automasking isn't "disabled". */
brush2.sculpt_brush_type = SCULPT_BRUSH_TYPE_SMOOTH;
brush2.automasking_flags = 0;
brush2.automasking_boundary_edges_propagation_steps = 1;
brush2.automasking_cavity_curve = sd2.automasking_cavity_curve;
brush_copy.sculpt_brush_type = SCULPT_BRUSH_TYPE_SMOOTH;
brush_copy.automasking_flags = 0;
brush_copy.automasking_boundary_edges_propagation_steps = 1;
brush_copy.automasking_cavity_curve = scene_copy.automasking_cavity_curve;
std::unique_ptr<auto_mask::Cache> automasking = auto_mask::cache_init(
*depsgraph, sd2, &brush2, ob);
*depsgraph, scene_copy, &brush_copy, ob);
undo::push_nodes(*depsgraph, ob, node_mask, undo::Type::Mask);
@@ -1171,14 +1134,11 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
bke::SpanAttributeWriter mask = attributes.lookup_or_add_for_write_span<float>(
".sculpt_mask", bke::AttrDomain::Point);
if (!mask) {
return OPERATOR_CANCELLED;
}
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
node_mask.slice(range).foreach_index([&](const int i) {
bake_mask_mesh(*depsgraph, ob, *automasking, mode, factor, nodes[i], tls, mask.span);
apply_mask_mesh(*depsgraph, ob, *automasking, mode, factor, nodes[i], tls, mask.span);
bke::pbvh::node_update_mask_mesh(mask.span, nodes[i]);
});
});
@@ -1192,7 +1152,7 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
node_mask.slice(range).foreach_index([&](const int i) {
bake_mask_grids(*depsgraph, ob, *automasking, mode, factor, nodes[i], tls);
apply_mask_grids(*depsgraph, ob, *automasking, mode, factor, nodes[i], tls);
bke::pbvh::node_update_mask_grids(key, masks, nodes[i]);
});
});
@@ -1205,7 +1165,7 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
LocalData &tls = all_tls.local();
node_mask.slice(range).foreach_index([&](const int i) {
bake_mask_bmesh(*depsgraph, ob, *automasking, mode, factor, nodes[i], tls);
apply_mask_bmesh(*depsgraph, ob, *automasking, mode, factor, nodes[i], tls);
bke::pbvh::node_update_mask_bmesh(mask_offset, nodes[i]);
});
});
@@ -1222,7 +1182,7 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void cavity_bake_ui(bContext *C, wmOperator *op)
static void mask_from_cavity_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
Scene *scene = CTX_data_scene(C);
@@ -1230,15 +1190,14 @@ static void cavity_bake_ui(bContext *C, wmOperator *op)
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
CavityBakeSettingsSource source = (CavityBakeSettingsSource)RNA_enum_get(op->ptr,
"settings_source");
MaskSettingsSource source = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
if (!sd) {
source = AUTOMASK_SETTINGS_OPERATOR;
source = MaskSettingsSource::Operator;
}
switch (source) {
case AUTOMASK_SETTINGS_OPERATOR: {
case MaskSettingsSource::Operator: {
uiItemR(layout, op->ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(layout, op->ptr, "mix_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(layout, op->ptr, "settings_source", UI_ITEM_NONE, nullptr, ICON_NONE);
@@ -1254,8 +1213,8 @@ static void cavity_bake_ui(bContext *C, wmOperator *op)
}
break;
}
case AUTOMASK_SETTINGS_BRUSH:
case AUTOMASK_SETTINGS_SCENE:
case MaskSettingsSource::Brush:
case MaskSettingsSource::Scene:
uiItemR(layout, op->ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(layout, op->ptr, "mix_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(layout, op->ptr, "settings_source", UI_ITEM_NONE, nullptr, ICON_NONE);
@@ -1269,39 +1228,39 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot)
ot->name = "Mask From Cavity";
ot->idname = "SCULPT_OT_mask_from_cavity";
ot->description = "Creates a mask based on the curvature of the surface";
ot->ui = cavity_bake_ui;
ot->ui = mask_from_cavity_ui;
static EnumPropertyItem mix_modes[] = {
{AUTOMASK_BAKE_MIX, "MIX", ICON_NONE, "Mix", ""},
{AUTOMASK_BAKE_MULTIPLY, "MULTIPLY", ICON_NONE, "Multiply", ""},
{AUTOMASK_BAKE_DIVIDE, "DIVIDE", ICON_NONE, "Divide", ""},
{AUTOMASK_BAKE_ADD, "ADD", ICON_NONE, "Add", ""},
{AUTOMASK_BAKE_SUBTRACT, "SUBTRACT", ICON_NONE, "Subtract", ""},
{int(ApplyMaskMode::Mix), "MIX", ICON_NONE, "Mix", ""},
{int(ApplyMaskMode::Multiply), "MULTIPLY", ICON_NONE, "Multiply", ""},
{int(ApplyMaskMode::Divide), "DIVIDE", ICON_NONE, "Divide", ""},
{int(ApplyMaskMode::Add), "ADD", ICON_NONE, "Add", ""},
{int(ApplyMaskMode::Subtract), "SUBTRACT", ICON_NONE, "Subtract", ""},
{0, nullptr, 0, nullptr, nullptr},
};
ot->exec = sculpt_bake_cavity_exec;
ot->exec = mask_from_cavity_exec;
ot->poll = SCULPT_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_enum(ot->srna, "mix_mode", mix_modes, AUTOMASK_BAKE_MIX, "Mode", "Mix mode");
RNA_def_enum(ot->srna, "mix_mode", mix_modes, int(ApplyMaskMode::Mix), "Mode", "Mix mode");
RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 5.0f, "Mix Factor", "", 0.0f, 1.0f);
static EnumPropertyItem settings_sources[] = {
{AUTOMASK_SETTINGS_OPERATOR,
{int(MaskSettingsSource::Operator),
"OPERATOR",
ICON_NONE,
"Operator",
"Use settings from operator properties"},
{AUTOMASK_SETTINGS_BRUSH, "BRUSH", ICON_NONE, "Brush", "Use settings from brush"},
{AUTOMASK_SETTINGS_SCENE, "SCENE", ICON_NONE, "Scene", "Use settings from scene"},
{int(MaskSettingsSource::Brush), "BRUSH", ICON_NONE, "Brush", "Use settings from brush"},
{int(MaskSettingsSource::Scene), "SCENE", ICON_NONE, "Scene", "Use settings from scene"},
{0, nullptr, 0, nullptr, nullptr}};
RNA_def_enum(ot->srna,
"settings_source",
settings_sources,
AUTOMASK_SETTINGS_OPERATOR,
int(MaskSettingsSource::Operator),
"Settings",
"Use settings from here");
@@ -1328,6 +1287,8 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "invert", false, "Cavity (Inverted)", "");
}
/** \} */
} // namespace mask
void operatortypes_sculpt()