81 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
83 const VArraySpan<int> face_sets = *attributes.lookup<
int>(
".sculpt_face_set",
90 for (const int id : face_sets.slice(range)) {
91 max = std::max(max, id);
95 [](
const int a,
const int b) {
return std::max(a,
b); });
102 if (cd_offset == -1) {
105 int next_face_set = 1;
110 next_face_set = std::max(next_face_set, fset);
113 return next_face_set + 1;
129 for (
const int i : face_sets.
span.index_range()) {
131 face_sets.
span[i] = new_id;
153 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
155 if (attributes.contains(
".sculpt_face_set")) {
158 attributes.
add<
int>(
".sculpt_face_set",
159 bke::AttrDomain::Face,
161 mesh.face_sets_color_default = 1;
168 if (!attributes.contains(
".sculpt_face_set")) {
169 attributes.
add<
int>(
".sculpt_face_set",
170 bke::AttrDomain::Face,
172 mesh.face_sets_color_default = 1;
174 return attributes.lookup_or_add_for_write_span<
int>(
".sculpt_face_set", bke::AttrDomain::Face);
179 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
193 mesh.face_sets_color_default = 1;
202 const VArray<int> attribute = *attributes.lookup_or_default(
203 ".sculpt_face_set", bke::AttrDomain::Face, 0);
217 for (
const int i :
verts.index_range()) {
218 if (unique == face_set::vert_has_unique_face_set(vert_to_face_map, face_sets,
verts[i])) {
237 const int node_start = i * key.
grid_area;
241 const int node_vert = node_start + offset;
242 if (factors[node_vert] == 0.0f) {
250 if (unique == face_set::vert_has_unique_face_set(
251 faces, corner_verts, vert_to_face_map, face_sets, subdiv_ccg, coord))
253 factors[node_vert] = 0.0f;
269 if (unique == face_set::vert_has_unique_face_set(face_set_offset, *vert)) {
292 *
static_cast<Mesh *
>(
object.data));
302 if (pbvh.
type() == bke::pbvh::Type::Mesh) {
305 TLS &tls = all_tls.
local();
306 const Span<int> faces = nodes[i].faces();
308 tls.new_face_sets.resize(faces.size());
311 calc_face_sets(faces, new_face_sets);
312 if (array_utils::indexed_data_equal<int>(face_sets.
span, faces, new_face_sets)) {
316 undo::push_node(
depsgraph,
object, &nodes[i], undo::Type::FaceSet);
318 node_changed[i] =
true;
321 else if (pbvh.
type() == bke::pbvh::Type::Grids) {
324 TLS &tls = all_tls.
local();
325 const Span<int> faces = bke::pbvh::node_face_indices_calc_grids(
328 tls.new_face_sets.resize(faces.size());
331 calc_face_sets(faces, new_face_sets);
332 if (array_utils::indexed_data_equal<int>(face_sets.
span, faces, new_face_sets)) {
336 undo::push_node(
depsgraph,
object, &nodes[i], undo::Type::FaceSet);
338 node_changed[i] =
true;
356 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
358 if (!attributes.contains(
".sculpt_face_set")) {
366 const int default_face_set = mesh.face_sets_color_default;
367 const VArraySpan face_sets = *attributes.lookup<
int>(
".sculpt_face_set", bke::AttrDomain::Face);
368 if (pbvh.
type() == bke::pbvh::Type::Mesh) {
371 const Span<int> faces = nodes[i].faces();
372 if (std::any_of(faces.begin(), faces.end(), [&](
const int face) {
373 return face_sets[face] != default_face_set;
376 undo::push_node(
depsgraph,
object, &nodes[i], undo::Type::FaceSet);
377 node_changed[i] =
true;
381 else if (pbvh.
type() == bke::pbvh::Type::Grids) {
386 const Span<int> faces = bke::pbvh::node_face_indices_calc_grids(
388 if (std::any_of(faces.begin(), faces.end(), [&](
const int face) {
389 return face_sets[face] != default_face_set;
392 undo::push_node(
depsgraph,
object, &nodes[i], undo::Type::FaceSet);
393 node_changed[i] =
true;
399 attributes.remove(
".sculpt_face_set");
417 if (pbvh.
type() == bke::pbvh::Type::BMesh) {
422 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
427 undo::push_begin(scene,
object, op);
432 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
434 case CreateMode::Masked: {
435 if (pbvh.
type() == bke::pbvh::Type::Mesh) {
437 const Span<int> corner_verts = mesh.corner_verts();
439 bke::AttrDomain::Face);
441 bke::AttrDomain::Point);
442 if (!mask.is_empty()) {
447 for (
const int i : indices.index_range()) {
448 if (!hide_poly.
is_empty() && hide_poly[indices[i]]) {
451 const Span<int> face_verts = corner_verts.
slice(faces[indices[i]]);
452 if (!std::any_of(face_verts.
begin(),
454 [&](
const int vert) { return mask[vert] > 0.5f; }))
458 face_sets[i] = next_face_set;
463 else if (pbvh.
type() == bke::pbvh::Type::Grids) {
467 const int grid_area = subdiv_ccg.
grid_area;
469 bke::AttrDomain::Face);
471 if (!masks.is_empty()) {
476 for (
const int i : indices.index_range()) {
477 if (!hide_poly.
is_empty() && hide_poly[indices[i]]) {
482 bke::ccg::face_range(faces, grid_area, indices[i]));
483 if (!std::any_of(face_masks.
begin(),
485 [&](
const float mask) { return mask > 0.5f; }))
489 face_sets[i] = next_face_set;
496 case CreateMode::Visible: {
497 const VArray<bool> hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
498 switch (array_utils::booleans_mix_calc(hide_poly)) {
499 case array_utils::BooleanMix::None:
500 case array_utils::BooleanMix::AllTrue:
501 case array_utils::BooleanMix::AllFalse:
507 case array_utils::BooleanMix::Mixed:
513 for (
const int i : indices.index_range()) {
514 if (!hide_poly_span[indices[i]]) {
515 face_sets[i] = next_face_set;
523 case CreateMode::All: {
528 face_sets.
fill(next_face_set);
532 case CreateMode::Selection: {
534 ".select_poly", bke::AttrDomain::Face,
false);
536 bke::AttrDomain::Face);
540 for (
const int i : indices.index_range()) {
541 if (select_poly[indices[i]]) {
542 if (!hide_poly.is_empty() && hide_poly[i]) {
545 face_sets[i] = next_face_set;
554 undo::push_end(
object);
563 ot->
name =
"Create Face Set";
564 ot->
idname =
"SCULPT_OT_face_sets_create";
573 {
int(CreateMode::Masked),
576 "Face Set from Masked",
577 "Create a new Face Set from the masked faces"},
578 {
int(CreateMode::Visible),
581 "Face Set from Visible",
582 "Create a new Face Set from the visible vertices"},
583 {
int(CreateMode::All),
586 "Face Set Full Mesh",
587 "Create an unique Face Set with all faces in the sculpt"},
588 {
int(CreateMode::Selection),
591 "Face Set from Edit Mode Selection",
592 "Create an Face Set corresponding to the Edit Mode face selection"},
593 {0,
nullptr, 0,
nullptr,
nullptr},
622 const Span<int> corner_edges = mesh->corner_edges();
630 const VArraySpan<bool> hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
633 int next_face_set = 1;
635 for (
const int i : faces.index_range()) {
636 if (!hide_poly.
is_empty() && hide_poly[i]) {
639 if (visited_faces[i]) {
642 std::queue<int> queue;
644 while (hidden_face_sets.contains(next_face_set)) {
647 face_sets.
span[i] = next_face_set;
648 visited_faces[i].set(
true);
651 while (!queue.empty()) {
652 const int face_i = queue.front();
655 for (
const int edge_i : corner_edges.
slice(faces[face_i])) {
657 if (neighbor_i == face_i) {
660 if (visited_faces[neighbor_i]) {
663 if (!hide_poly.
is_empty() && hide_poly[neighbor_i]) {
666 if (!test_fn(face_i, edge_i, neighbor_i)) {
670 face_sets.
span[neighbor_i] = next_face_set;
671 visited_faces[neighbor_i].set(
true);
672 queue.push(neighbor_i);
692 hidden_face_sets.
add(face_sets[i]);
696 return hidden_face_sets;
717 if (pbvh.
type() == bke::pbvh::Type::BMesh) {
722 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
727 undo::push_begin(scene, ob, op);
728 undo::push_nodes(*
depsgraph, ob, node_mask, undo::Type::FaceSet);
736 case InitMode::LooseParts: {
737 const VArray<bool> hide_poly = *attributes.lookup_or_default<
bool>(
738 ".hide_poly", bke::AttrDomain::Face,
false);
739 init_flood_fill(ob, [&](
const int from_face,
const int ,
const int to_face) {
740 return hide_poly[from_face] == hide_poly[to_face];
744 case InitMode::Materials: {
746 const VArraySpan<int> material_indices = *attributes.lookup_or_default<
int>(
747 "material_index", bke::AttrDomain::Face, 0);
749 bke::AttrDomain::Face);
750 for (
const int i :
IndexRange(mesh->faces_num)) {
751 if (!hide_poly.is_empty() && hide_poly[i]) {
757 face_sets.
span[i] = material_indices[i] + 1;
763 case InitMode::Normals: {
765 init_flood_fill(ob, [&](
const int from_face,
const int ,
const int to_face) ->
bool {
766 return std::abs(
math::dot(face_normals[from_face], face_normals[to_face])) > threshold;
770 case InitMode::UVSeams: {
771 const VArraySpan<bool> uv_seams = *mesh->attributes().lookup_or_default<
bool>(
772 ".uv_seam", bke::AttrDomain::Edge,
false);
774 [&](
const int ,
const int edge,
const int ) ->
bool {
775 return !uv_seams[edge];
779 case InitMode::Creases: {
781 "crease_edge", bke::AttrDomain::Edge, 0.0f);
783 [&](
const int ,
const int edge,
const int ) ->
bool {
784 return creases[edge] < threshold;
788 case InitMode::SharpEdges: {
789 const VArraySpan<bool> sharp_edges = *mesh->attributes().lookup_or_default<
bool>(
790 "sharp_edge", bke::AttrDomain::Edge,
false);
792 [&](
const int ,
const int edge,
const int ) ->
bool {
793 return !sharp_edges[edge];
797 case InitMode::BevelWeight: {
799 "bevel_weight_edge", bke::AttrDomain::Edge, 0.0f);
801 [&](
const int ,
const int edge,
const int ) ->
bool {
802 return bevel_weights[edge] < threshold;
806 case InitMode::FaceSetBoundaries: {
808 init_flood_fill(ob, [&](
const int from_face,
const int ,
const int to_face) ->
bool {
809 return face_sets_copy[from_face] == face_sets_copy[to_face];
826 ot->
name =
"Init Face Sets";
827 ot->
idname =
"SCULPT_OT_face_sets_init";
836 {
int(InitMode::LooseParts),
839 "Face Sets from Loose Parts",
840 "Create a Face Set per loose part in the mesh"},
841 {
int(InitMode::Materials),
844 "Face Sets from Material Slots",
845 "Create a Face Set per Material Slot"},
846 {
int(InitMode::Normals),
849 "Face Sets from Mesh Normals",
850 "Create Face Sets for Faces that have similar normal"},
851 {
int(InitMode::UVSeams),
854 "Face Sets from UV Seams",
855 "Create Face Sets using UV Seams as boundaries"},
856 {
int(InitMode::Creases),
859 "Face Sets from Edge Creases",
860 "Create Face Sets using Edge Creases as boundaries"},
861 {
int(InitMode::BevelWeight),
864 "Face Sets from Bevel Weight",
865 "Create Face Sets using Bevel Weights as boundaries"},
866 {
int(InitMode::SharpEdges),
869 "Face Sets from Sharp Edges",
870 "Create Face Sets using Sharp Edges as boundaries"},
871 {
int(InitMode::FaceSetBoundaries),
872 "FACE_SET_BOUNDARIES",
874 "Face Sets from Face Set Boundaries",
875 "Create a Face Set per isolated Face Set"},
876 {0,
nullptr, 0,
nullptr,
nullptr},
886 "Minimum value to consider a certain attribute a boundary when creating the Face Sets",
904 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
907 ".hide_poly", bke::AttrDomain::Face);
917 if (pbvh.
type() == bke::pbvh::Type::Mesh) {
920 TLS &tls = all_tls.
local();
921 const Span<int> faces = nodes[i].faces();
923 tls.new_hide.resize(faces.size());
926 calc_hide(faces, new_hide);
927 if (array_utils::indexed_data_equal<bool>(hide_poly.
span, faces, new_hide)) {
931 undo::push_node(
depsgraph,
object, &nodes[i], undo::Type::HideFace);
933 node_changed[i] =
true;
936 else if (pbvh.
type() == bke::pbvh::Type::Grids) {
939 TLS &tls = all_tls.
local();
940 const Span<int> faces = bke::pbvh::node_face_indices_calc_grids(
943 tls.new_hide.resize(faces.size());
946 calc_hide(faces, new_hide);
947 if (array_utils::indexed_data_equal<bool>(hide_poly.
span, faces, new_hide)) {
951 undo::push_node(
depsgraph,
object, &nodes[i], undo::Type::HideFace);
953 node_changed[i] =
true;
960 const IndexMask changed_nodes = IndexMask::from_bools(node_changed, memory);
964 hide::sync_all_from_faces(
object);
970 switch (bke::object::pbvh_get(
object)->type()) {
971 case bke::pbvh::Type::Mesh:
972 hide::mesh_show_all(
depsgraph,
object, node_mask);
974 case bke::pbvh::Type::Grids:
975 hide::grids_show_all(
depsgraph,
object, node_mask);
977 case bke::pbvh::Type::BMesh:
995 if (pbvh.
type() == bke::pbvh::Type::BMesh) {
1003 undo::push_begin(scene,
object, op);
1006 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1009 const VArraySpan<bool> hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
1010 const VArraySpan<int> face_sets = *attributes.lookup<
int>(
".sculpt_face_set",
1011 bke::AttrDomain::Face);
1014 case VisibilityMode::Toggle: {
1015 if (hide_poly.
contains(
true) || face_sets.is_empty()) {
1022 hide[i] = face_sets[faces[i]] != active_face_set;
1028 case VisibilityMode::ShowActive:
1029 if (face_sets.is_empty()) {
1036 if (face_sets[faces[i]] == active_face_set) {
1043 case VisibilityMode::HideActive:
1044 if (face_sets.is_empty()) {
1054 if (face_sets[faces[i]] == active_face_set) {
1065 if (
ELEM(mode, VisibilityMode::Toggle, VisibilityMode::ShowActive)) {
1067 if (std::holds_alternative<std::monostate>(ss.
active_vert())) {
1080 undo::push_end(
object);
1082 bke::pbvh::update_visibility(
object, pbvh);
1084 islands::invalidate(*
object.sculpt);
1085 hide::tag_update_visibility(*C);
1112 ot->
name =
"Face Sets Visibility";
1113 ot->
idname =
"SCULPT_OT_face_set_change_visibility";
1114 ot->
description =
"Change the visibility of the Face Sets of the sculpt";
1123 {
int(VisibilityMode::Toggle),
1126 "Toggle Visibility",
1127 "Hide all Face Sets except for the active one"},
1128 {
int(VisibilityMode::ShowActive),
1131 "Show Active Face Set",
1132 "Show Active Face Set"},
1133 {
int(VisibilityMode::HideActive),
1136 "Hide Active Face Sets",
1137 "Hide Active Face Sets"},
1138 {0,
nullptr, 0,
nullptr,
nullptr},
1156 if (pbvh.
type() == bke::pbvh::Type::BMesh) {
1163 if (!attributes.contains(
".sculpt_face_set")) {
1167 const VArray<int> face_sets = *attributes.lookup<
int>(
".sculpt_face_set", bke::AttrDomain::Face);
1170 max_ii(0, mesh->faces_num - 1));
1171 mesh->face_sets_color_default = face_sets[random_index];
1173 mesh->face_sets_color_seed += 1;
1176 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1186 ot->
name =
"Randomize Face Sets Colors";
1187 ot->
idname =
"SCULPT_OT_face_sets_randomize_colors";
1188 ot->
description =
"Generates a new set of random colors to render the Face Sets in the viewport";
1208 const int active_face_set_id,
1209 const bool modify_hidden,
1213 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
1215 const Span<int> corner_verts = mesh.corner_verts();
1219 BLI_assert(attributes.contains(
".sculpt_face_set"));
1221 const VArraySpan<bool> hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
1224 undo::push_begin(scene,
object, op);
1227 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1230 for (
const int i : indices.index_range()) {
1231 const int face = indices[i];
1232 if (!modify_hidden && !hide_poly.
is_empty() && hide_poly[face]) {
1235 if (mode == EditMode::Grow) {
1236 for (
const int vert : corner_verts.
slice(faces[face])) {
1237 for (
const int neighbor_face_index : vert_to_face_map[vert]) {
1238 if (neighbor_face_index == face) {
1241 if (prev_face_sets[neighbor_face_index] == active_face_set_id) {
1242 face_sets[i] = active_face_set_id;
1248 if (prev_face_sets[face] == active_face_set_id) {
1249 for (
const int vert_i : corner_verts.
slice(faces[face])) {
1250 for (
const int neighbor_face_index : vert_to_face_map[vert_i]) {
1251 if (neighbor_face_index == face) {
1254 if (prev_face_sets[neighbor_face_index] != active_face_set_id) {
1255 face_sets[i] = prev_face_sets[neighbor_face_index];
1264 undo::push_end(
object);
1269 const Mesh &mesh = *
static_cast<const Mesh *
>(
object.data);
1271 const VArraySpan<bool> hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
1272 const VArraySpan<int> face_sets = *attributes.lookup<
int>(
".sculpt_face_set",
1273 bke::AttrDomain::Face);
1275 if (face_sets.is_empty()) {
1279 if (check_visible_only) {
1280 for (
const int i : face_sets.index_range()) {
1281 if (!hide_poly.
is_empty() && hide_poly[i]) {
1284 first_face_set = face_sets[i];
1289 first_face_set = face_sets[0];
1296 for (
const int i : face_sets.index_range()) {
1297 if (check_visible_only && !hide_poly.
is_empty() && hide_poly[i]) {
1300 if (face_sets[i] != first_face_set) {
1311 const VArraySpan<bool> hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
1312 const VArraySpan<int> face_sets = *attributes.lookup<
int>(
".sculpt_face_set",
1313 bke::AttrDomain::Face);
1322 convert_params.calc_face_normal =
true;
1332 if (!modify_hidden && !hide_poly.
is_empty() && hide_poly[face_index]) {
1350 const int active_face_set_id,
1352 const float strength)
1357 boundary::ensure_boundary_info(ob);
1364 const VArraySpan hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
1365 const VArraySpan face_sets = *attributes.lookup<
int>(
".sculpt_face_set", bke::AttrDomain::Face);
1368 for (
const int vert : positions.index_range()) {
1369 if (boundary::vert_is_boundary(vert_to_face_map, hide_poly, boundary_verts, vert)) {
1372 if (!
vert_has_face_set(vert_to_face_map, face_sets, vert, active_face_set_id)) {
1378 fair_verts[vert] =
true;
1389 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1398 for (
const int i :
verts.index_range()) {
1399 translations[i] = new_positions[
verts[i]] - positions[
verts[i]];
1409 const bool modify_hidden)
1412 if (pbvh.
type() == bke::pbvh::Type::BMesh) {
1417 if (mode == EditMode::DeleteGeometry) {
1418 if (pbvh.
type() == bke::pbvh::Type::Grids) {
1432 if (
ELEM(mode, EditMode::FairPositions, EditMode::FairTangency)) {
1433 if (pbvh.
type() == bke::pbvh::Type::Grids) {
1441 if (
ELEM(mode, EditMode::Grow, EditMode::Shrink)) {
1442 if (pbvh.
type() == bke::pbvh::Type::Mesh) {
1443 const Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
1445 if (!attributes.contains(
".sculpt_face_set")) {
1461 undo::geometry_begin(scene, ob, op);
1463 undo::geometry_end(ob);
1478 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1482 undo::push_begin(scene, ob, op);
1483 undo::push_nodes(
depsgraph, ob, node_mask, undo::Type::Position);
1488 case EditMode::FairPositions:
1491 case EditMode::FairTangency:
1498 bke::pbvh::update_bounds(
depsgraph, ob, pbvh);
1530 const int active_face_set =
RNA_int_get(op->
ptr,
"active_face_set");
1535 case EditMode::DeleteGeometry:
1538 case EditMode::Grow:
1539 case EditMode::Shrink:
1542 case EditMode::FairPositions:
1543 case EditMode::FairTangency:
1581 ot->
name =
"Edit Face Set";
1582 ot->
idname =
"SCULPT_OT_face_set_edit";
1592 ot->
srna,
"active_face_set", 1, 0, INT_MAX,
"Active Face Set",
"", 0, 64);
1596 {
int(EditMode::Grow),
1600 "Grows the Face Sets boundary by one face based on mesh topology"},
1601 {
int(EditMode::Shrink),
1605 "Shrinks the Face Sets boundary by one face based on mesh topology"},
1606 {
int(EditMode::DeleteGeometry),
1610 "Deletes the faces that are assigned to the Face Set"},
1611 {
int(EditMode::FairPositions),
1615 "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
1616 "vertex positions"},
1617 {
int(EditMode::FairTangency),
1621 "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
1623 {0,
nullptr, 0,
nullptr,
nullptr},
1632 "Apply the edit operation to hidden geometry");
1653 undo::push_begin(scene, *gesture_data.
vc.
obact, &op);
1662 Mesh &mesh = *
static_cast<Mesh *
>(
object.data);
1669 const Span<int> corner_verts = mesh.corner_verts();
1670 const VArraySpan<bool> hide_poly = *attributes.lookup<
bool>(
".hide_poly", bke::AttrDomain::Face);
1680 if (pbvh.
type() == bke::pbvh::Type::Mesh) {
1683 undo::push_node(
depsgraph, *gesture_data.
vc.
obact, &nodes[i], undo::Type::FaceSet);
1684 bool any_updated =
false;
1685 for (
const int face : nodes[i].faces()) {
1686 if (!hide_poly.
is_empty() && hide_poly[face]) {
1690 const float3 face_center = bke::mesh::face_center_calc(positions, face_verts);
1691 const float3 face_normal = bke::mesh::face_normal_calc(positions, face_verts);
1692 if (!gesture::is_affected(gesture_data, face_center, face_normal)) {
1695 face_sets.span[face] = new_face_set;
1699 node_changed[i] =
true;
1703 else if (pbvh.
type() == bke::pbvh::Type::Grids) {
1706 TLS &tls = all_tls.
local();
1707 undo::push_node(
depsgraph, *gesture_data.
vc.
obact, &nodes[i], undo::Type::FaceSet);
1708 const Span<int> node_faces = bke::pbvh::node_face_indices_calc_grids(
1711 bool any_updated =
false;
1712 for (
const int face : node_faces) {
1713 if (!hide_poly.
is_empty() && hide_poly[face]) {
1717 const float3 face_center = bke::mesh::face_center_calc(positions, face_verts);
1718 const float3 face_normal = bke::mesh::face_normal_calc(positions, face_verts);
1719 if (!gesture::is_affected(gesture_data, face_center, face_normal)) {
1722 face_sets.span[face] = new_face_set;
1726 node_changed[i] =
true;
1750 undo::push_node(
depsgraph, *gesture_data.
vc.
obact, &nodes[i], undo::Type::FaceSet);
1752 bool any_updated =
false;
1759 if (!gesture::is_affected(gesture_data, center, face->no)) {
1767 node_changed[i] =
true;
1772 const IndexMask changed_nodes = IndexMask::from_bools(node_changed, memory);
1781 switch (bke::object::pbvh_get(*gesture_data.
vc.
obact)->type()) {
1782 case bke::pbvh::Type::Grids:
1783 case bke::pbvh::Type::Mesh:
1786 case bke::pbvh::Type::BMesh:
1794 undo::push_end(*gesture_data.
vc.
obact);
1801 MEM_cnew<FaceSetOperation>(__func__));
1809 face_set_operation->
new_face_set_id = face_set::find_next_available_id(
object);
1825 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_box(C, op);
1826 if (!gesture_data) {
1830 gesture::apply(*C, *gesture_data, *op);
1847 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_lasso(C, op);
1848 if (!gesture_data) {
1852 gesture::apply(*C, *gesture_data, *op);
1869 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_line(C, op);
1870 if (!gesture_data) {
1874 gesture::apply(*C, *gesture_data, *op);
1891 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_polyline(C, op);
1892 if (!gesture_data) {
1896 gesture::apply(*C, *gesture_data, *op);
1902 ot->
name =
"Face Set Lasso Gesture";
1903 ot->
idname =
"SCULPT_OT_face_set_polyline_gesture";
1904 ot->
description =
"Add a face set in a shape defined by the cursor";
1915 gesture::operator_properties(
ot, gesture::ShapeType::Lasso);
1920 ot->
name =
"Face Set Box Gesture";
1921 ot->
idname =
"SCULPT_OT_face_set_box_gesture";
1922 ot->
description =
"Add a face set in a rectangle defined by the cursor";
1933 gesture::operator_properties(
ot, gesture::ShapeType::Box);
1938 ot->
name =
"Face Set Lasso Gesture";
1939 ot->
idname =
"SCULPT_OT_face_set_lasso_gesture";
1940 ot->
description =
"Add a face set in a shape defined by the cursor";
1951 gesture::operator_properties(
ot, gesture::ShapeType::Lasso);
1956 ot->
name =
"Face Set Line Gesture";
1957 ot->
idname =
"SCULPT_OT_face_set_line_gesture";
1958 ot->
description =
"Add a face set to one side of a line defined by the cursor";
1969 gesture::operator_properties(
ot, gesture::ShapeType::Line);
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
void BKE_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode)
@ BKE_MESH_BATCH_DIRTY_ALL
@ MESH_FAIRING_DEPTH_POSITION
@ MESH_FAIRING_DEPTH_TANGENCY
void BKE_mesh_prefair_and_fair_verts(Mesh *mesh, blender::MutableSpan< blender::float3 > deform_vert_positions, const bool affected_verts[], eMeshFairingDepth depth)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_original_mesh(const Object *object)
#define SCULPT_FACE_SET_NONE
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
void BKE_sculptsession_free_pbvh(Object &object)
A BVH for high poly meshes.
const blender::Set< BMFace *, 0 > & BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
#define BLI_assert_unreachable()
BLI_INLINE float BLI_hash_int_01(unsigned int k)
MINLINE int max_ii(int a, int b)
MINLINE int clamp_i(int value, int min, int max)
void mul_m4_v3(const float M[4][4], float r[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define POINTER_OFFSET(v, ofs)
void DEG_id_tag_update(ID *id, unsigned int flags)
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
@ OPTYPE_DEPENDS_ON_CURSOR
#define BM_ELEM_CD_SET_INT(ele, offset, f)
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
#define BM_elem_index_get(ele)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_flag_test(ele, hflag)
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
#define BM_ITER_MESH(ele, iter, bm, itype)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
#define BMALLOC_TEMPLATE_FROM_ME(...)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
MutableSpan< T > as_mutable_span()
constexpr int64_t size() const
constexpr void fill(const T &value) const
constexpr Span< T > as_span() const
constexpr IndexRange index_range() const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr const T * end() const
constexpr IndexRange index_range() const
constexpr const T * begin() const
constexpr bool is_empty() const
constexpr bool contains(const T &value) const
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
void tag_positions_changed(const IndexMask &node_mask)
Span< NodeT > nodes() const
void tag_face_sets_changed(const IndexMask &node_mask)
void tag_visibility_changed(const IndexMask &node_mask)
int64_t min_array_size() const
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
pbvh::Tree * pbvh_get(Object &object)
static int gesture_lasso_exec(bContext *C, wmOperator *op)
static void face_hide_update(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const FunctionRef< void(Span< int >, MutableSpan< bool >)> calc_hide)
static bool edit_is_operation_valid(const Object &object, const EditMode mode, const bool modify_hidden)
void filter_verts_with_unique_face_sets_mesh(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const bool unique, const Span< int > verts, const MutableSpan< float > factors)
int find_next_available_id(Object &object)
int ensure_face_sets_bmesh(Object &object)
static void gesture_apply_for_symmetry_pass(bContext &, gesture::GestureData &gesture_data)
static void edit_fairing(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const int active_face_set_id, const eMeshFairingDepth fair_order, const float strength)
static int change_visibility_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int gesture_polyline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool vert_has_unique_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, int vert)
bool vert_has_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert, const int face_set)
void SCULPT_OT_face_set_lasso_gesture(wmOperatorType *ot)
static int gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void gesture_begin(bContext &C, wmOperator &op, gesture::GestureData &gesture_data)
bool create_face_sets_mesh(Object &object)
static int gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void initialize_none_to_id(Mesh *mesh, int new_id)
static bool edit_op_init(bContext *C, wmOperator *op)
void SCULPT_OT_face_set_line_gesture(wmOperatorType *ot)
void SCULPT_OT_face_set_polyline_gesture(wmOperatorType *ot)
static void clear_face_sets(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
static void delete_geometry(Object &ob, const int active_face_set_id, const bool modify_hidden)
void SCULPT_OT_face_sets_init(wmOperatorType *ot)
int active_update_and_get(bContext *C, Object &ob, const float mval_fl[2])
static void edit_grow_shrink(const Depsgraph &depsgraph, const Scene &scene, Object &object, const EditMode mode, const int active_face_set_id, const bool modify_hidden, wmOperator *op)
void filter_verts_with_unique_face_sets_bmesh(int face_set_offset, const bool unique, const Set< BMVert *, 0 > &verts, const MutableSpan< float > factors)
static void show_all(Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
Array< int > duplicate_face_sets(const Mesh &mesh)
void SCULPT_OT_face_sets_create(wmOperatorType *ot)
Set< int > gather_hidden_face_sets(const Span< bool > hide_poly, const Span< int > face_sets)
static int create_op_exec(bContext *C, wmOperator *op)
static void gesture_apply_mesh(gesture::GestureData &gesture_data, const IndexMask &node_mask)
void SCULPT_OT_face_set_change_visibility(wmOperatorType *ot)
void filter_verts_with_unique_face_sets_grids(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const SubdivCCG &subdiv_ccg, const bool unique, const Span< int > grids, const MutableSpan< float > factors)
static int init_op_exec(bContext *C, wmOperator *op)
void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
static bool check_single_face_set(const Object &object, const bool check_visible_only)
static int edit_op_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int edit_op_exec(bContext *C, wmOperator *op)
static int gesture_box_exec(bContext *C, wmOperator *op)
bke::SpanAttributeWriter< int > ensure_face_sets_mesh(Mesh &mesh)
static void face_sets_update(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const FunctionRef< void(Span< int >, MutableSpan< int >)> calc_face_sets)
static int change_visibility_exec(bContext *C, wmOperator *op)
void SCULPT_OT_face_sets_edit(wmOperatorType *ot)
static void gesture_end(bContext &, gesture::GestureData &gesture_data)
static void gesture_apply_bmesh(gesture::GestureData &gesture_data, const IndexMask &node_mask)
static void init_operation(gesture::GestureData &gesture_data, wmOperator &)
void SCULPT_OT_face_set_box_gesture(wmOperatorType *ot)
static int randomize_colors_exec(bContext *C, wmOperator *)
static int gesture_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void edit_modify_coordinates(bContext *C, Object &ob, const int active_face_set, const EditMode mode, wmOperator *op)
static void init_flood_fill(Object &ob, const FaceSetsFloodFillFn &test_fn)
static int gesture_line_exec(bContext *C, wmOperator *op)
int active_face_set_get(const Object &object)
static int gesture_polyline_exec(bContext *C, wmOperator *op)
static void edit_modify_geometry(bContext *C, Object &ob, const int active_face_set, const bool modify_hidden, wmOperator *op)
void flush_update_done(const bContext *C, Object &ob, UpdateType update_type)
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
void flush_update_step(bContext *C, UpdateType update_type)
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
void SCULPT_vertex_random_access_ensure(Object &object)
bool SCULPT_mode_poll_view3d(bContext *C)
bool SCULPT_mode_poll(bContext *C)
void SCULPT_tag_update_overlays(bContext *C)
struct SculptSession * sculpt
SculptVertexInfo vertex_info
ActiveVert active_vert() const
blender::Array< int > edge_to_face_offsets
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
blender::GroupedSpan< int > edge_to_face_map
blender::Array< int > edge_to_face_indices
blender::BitVector boundary
blender::Array< float > masks
float average_stroke_accum[3]
int average_stroke_counter
MutableVArraySpan< T > span
Vector< float3 > translations
void(* end)(bContext &, GestureData &)
void(* begin)(bContext &, wmOperator &, GestureData &)
void(* apply_for_symmetry_pass)(bContext &, GestureData &)
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_gesture_polyline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_polyline_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
void WM_operator_properties_border(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_polyline(wmOperatorType *ot)