Blender V4.5
sculpt_face_set.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#include "sculpt_face_set.hh"
9
10#include <cmath>
11#include <cstdlib>
12#include <queue>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_array.hh"
17#include "BLI_array_utils.hh"
18#include "BLI_bit_vector.hh"
20#include "BLI_function_ref.hh"
21#include "BLI_hash.h"
22#include "BLI_math_matrix.h"
23#include "BLI_math_vector.h"
24#include "BLI_math_vector.hh"
26#include "BLI_span.hh"
27#include "BLI_task.hh"
28#include "BLI_vector.hh"
29
30#include "BLT_translation.hh"
31
33#include "DNA_object_types.h"
34#include "DNA_scene_types.h"
35
36#include "BKE_attribute.hh"
37#include "BKE_ccg.hh"
38#include "BKE_context.hh"
39#include "BKE_customdata.hh"
40#include "BKE_layer.hh"
41#include "BKE_mesh.hh"
42#include "BKE_mesh_fair.hh"
43#include "BKE_mesh_mapping.hh"
44#include "BKE_object.hh"
45#include "BKE_paint.hh"
46#include "BKE_paint_bvh.hh"
47#include "BKE_subdiv_ccg.hh"
48
49#include "DEG_depsgraph.hh"
50
51#include "WM_api.hh"
52#include "WM_types.hh"
53
54#include "ED_sculpt.hh"
55
56#include "mesh_brush_common.hh"
57#include "paint_hide.hh"
58#include "sculpt_automask.hh"
59#include "sculpt_boundary.hh"
60#include "sculpt_gesture.hh"
61#include "sculpt_intern.hh"
62#include "sculpt_islands.hh"
63#include "sculpt_undo.hh"
64
65#include "RNA_access.hh"
66#include "RNA_define.hh"
67
68#include "bmesh.hh"
69
71
72/* -------------------------------------------------------------------- */
75
77{
78 SculptSession &ss = *object.sculpt;
79 switch (bke::object::pbvh_get(object)->type()) {
82 Mesh &mesh = *static_cast<Mesh *>(object.data);
83 const bke::AttributeAccessor attributes = mesh.attributes();
84 const VArraySpan<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
87 face_sets.index_range(),
88 4096,
89 1,
90 [&](const IndexRange range, int max) {
91 for (const int id : face_sets.slice(range)) {
92 max = std::max(max, id);
93 }
94 return max;
95 },
96 [](const int a, const int b) { return std::max(a, b); });
97 return max + 1;
98 }
100 BMesh &bm = *ss.bm;
101 const int cd_offset = CustomData_get_offset_named(
102 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
103 if (cd_offset == -1) {
104 /* Default face set ID is 1, so the next available id should never be 1 */
105 return 2;
106 }
107 int next_face_set = 1;
108 BMIter iter;
109 BMFace *f;
110 BM_ITER_MESH (f, &iter, &bm, BM_FACES_OF_MESH) {
111 const int fset = *static_cast<const int *>(POINTER_OFFSET(f->head.data, cd_offset));
112 next_face_set = std::max(next_face_set, fset);
113 }
114
115 return next_face_set + 1;
116 }
117 }
119 return 0;
120}
121
122void initialize_none_to_id(Mesh *mesh, const int new_id)
123{
124 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
125 bke::SpanAttributeWriter<int> face_sets = attributes.lookup_for_write_span<int>(
126 ".sculpt_face_set");
127 if (!face_sets) {
128 return;
129 }
130
131 for (const int i : face_sets.span.index_range()) {
132 if (face_sets.span[i] == SCULPT_FACE_SET_NONE) {
133 face_sets.span[i] = new_id;
134 }
135 }
136 face_sets.finish();
137}
138
139int active_update_and_get(bContext *C, Object &ob, const float mval[2])
140{
141 if (!ob.sculpt) {
143 }
144
146 if (!cursor_geometry_info_update(C, &gi, mval, false)) {
148 }
149
150 return active_face_set_get(ob);
151}
152
154{
155 Mesh &mesh = *static_cast<Mesh *>(object.data);
156 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
157 if (attributes.contains(".sculpt_face_set")) {
158 return false;
159 }
160 attributes.add<int>(".sculpt_face_set",
163 mesh.face_sets_color_default = 1;
164 return true;
165}
166
168{
169 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
170 if (!attributes.contains(".sculpt_face_set")) {
171 attributes.add<int>(".sculpt_face_set",
174 mesh.face_sets_color_default = 1;
175 }
176 return attributes.lookup_or_add_for_write_span<int>(".sculpt_face_set", bke::AttrDomain::Face);
177}
178
180{
181 Mesh &mesh = *static_cast<Mesh *>(object.data);
182 SculptSession &ss = *object.sculpt;
183 BMesh &bm = *ss.bm;
184 if (!CustomData_has_layer_named(&bm.pdata, CD_PROP_INT32, ".sculpt_face_set")) {
185 BM_data_layer_add_named(&bm, &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
186 const int offset = CustomData_get_offset_named(&bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
187 if (offset == -1) {
188 return -1;
189 }
190 BMIter iter;
191 BMFace *face;
192 BM_ITER_MESH (face, &iter, &bm, BM_FACES_OF_MESH) {
193 BM_ELEM_CD_SET_INT(face, offset, 1);
194 }
195 mesh.face_sets_color_default = 1;
196 return offset;
197 }
198 return CustomData_get_offset_named(&bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
199}
200
202{
203 const bke::AttributeAccessor attributes = mesh.attributes();
204 const VArray<int> attribute = *attributes.lookup_or_default(
205 ".sculpt_face_set", bke::AttrDomain::Face, 0);
206 Array<int> face_sets(attribute.size());
207 array_utils::copy(attribute, face_sets.as_mutable_span());
208 return face_sets;
209}
210
212 const Span<int> face_sets,
213 const bool unique,
214 const Span<int> verts,
215 const MutableSpan<float> factors)
216{
217 BLI_assert(verts.size() == factors.size());
218
219 for (const int i : verts.index_range()) {
220 if (unique == face_set::vert_has_unique_face_set(vert_to_face_map, face_sets, verts[i])) {
221 factors[i] = 0.0f;
222 }
223 }
224}
225
227 const Span<int> corner_verts,
228 const GroupedSpan<int> vert_to_face_map,
229 const Span<int> face_sets,
230 const SubdivCCG &subdiv_ccg,
231 const bool unique,
232 const Span<int> grids,
233 const MutableSpan<float> factors)
234{
235 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
236 BLI_assert(grids.size() * key.grid_area == factors.size());
237
238 for (const int i : grids.index_range()) {
239 const int node_start = i * key.grid_area;
240 for (const int y : IndexRange(key.grid_size)) {
241 for (const int x : IndexRange(key.grid_size)) {
242 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
243 const int node_vert = node_start + offset;
244 if (factors[node_vert] == 0.0f) {
245 continue;
246 }
247
248 SubdivCCGCoord coord{};
249 coord.grid_index = grids[i];
250 coord.x = x;
251 coord.y = y;
253 faces, corner_verts, vert_to_face_map, face_sets, subdiv_ccg, coord))
254 {
255 factors[node_vert] = 0.0f;
256 }
257 }
258 }
259 }
260}
261
263 const bool unique,
264 const Set<BMVert *, 0> &verts,
265 const MutableSpan<float> factors)
266{
267 BLI_assert(verts.size() == factors.size());
268
269 int i = 0;
270 for (const BMVert *vert : verts) {
271 if (unique == face_set::vert_has_unique_face_set(face_set_offset, *vert)) {
272 factors[i] = 0.0f;
273 }
274 i++;
275 }
276}
277
279
280/* -------------------------------------------------------------------- */
284
285static void face_sets_update(const Depsgraph &depsgraph,
286 Object &object,
287 const IndexMask &node_mask,
288 const FunctionRef<void(Span<int>, MutableSpan<int>)> calc_face_sets)
289{
290 SculptSession &ss = *object.sculpt;
291 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
292
294 *static_cast<Mesh *>(object.data));
295
296 struct TLS {
297 Vector<int> face_indices;
298 Vector<int> new_face_sets;
299 };
300
301 Array<bool> node_changed(pbvh.nodes_num(), false);
302
304 if (pbvh.type() == bke::pbvh::Type::Mesh) {
306 node_mask.foreach_index(GrainSize(1), [&](const int i) {
307 TLS &tls = all_tls.local();
308 const Span<int> faces = nodes[i].faces();
309
310 tls.new_face_sets.resize(faces.size());
311 MutableSpan<int> new_face_sets = tls.new_face_sets;
312 gather_data_mesh(face_sets.span.as_span(), faces, new_face_sets);
313 calc_face_sets(faces, new_face_sets);
314 if (array_utils::indexed_data_equal<int>(face_sets.span, faces, new_face_sets)) {
315 return;
316 }
317
319 scatter_data_mesh(new_face_sets.as_span(), faces, face_sets.span);
320 node_changed[i] = true;
321 });
322 }
323 else if (pbvh.type() == bke::pbvh::Type::Grids) {
325 node_mask.foreach_index(GrainSize(1), [&](const int i) {
326 TLS &tls = all_tls.local();
328 *ss.subdiv_ccg, nodes[i], tls.face_indices);
329
330 tls.new_face_sets.resize(faces.size());
331 MutableSpan<int> new_face_sets = tls.new_face_sets;
332 gather_data_mesh(face_sets.span.as_span(), faces, new_face_sets);
333 calc_face_sets(faces, new_face_sets);
334 if (array_utils::indexed_data_equal<int>(face_sets.span, faces, new_face_sets)) {
335 return;
336 }
337
339 scatter_data_mesh(new_face_sets.as_span(), faces, face_sets.span);
340 node_changed[i] = true;
341 });
342 }
343
344 IndexMaskMemory memory;
345 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
346 face_sets.finish();
347}
348
349enum class CreateMode {
352 All = 2,
353 Selection = 3,
354};
355
356static void clear_face_sets(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
357{
358 Mesh &mesh = *static_cast<Mesh *>(object.data);
359 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
360 if (!attributes.contains(".sculpt_face_set")) {
361 return;
362 }
363 SculptSession &ss = *object.sculpt;
364 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
365
366 Array<bool> node_changed(pbvh.nodes_num(), false);
367
368 const int default_face_set = mesh.face_sets_color_default;
369 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
370 if (pbvh.type() == bke::pbvh::Type::Mesh) {
372 node_mask.foreach_index(GrainSize(1), [&](const int i) {
373 const Span<int> faces = nodes[i].faces();
374 if (std::any_of(faces.begin(), faces.end(), [&](const int face) {
375 return face_sets[face] != default_face_set;
376 }))
377 {
379 node_changed[i] = true;
380 }
381 });
382 }
383 else if (pbvh.type() == bke::pbvh::Type::Grids) {
386 node_mask.foreach_index(GrainSize(1), [&](const int i) {
387 Vector<int> &face_indices = all_face_indices.local();
389 *ss.subdiv_ccg, nodes[i], face_indices);
390 if (std::any_of(faces.begin(), faces.end(), [&](const int face) {
391 return face_sets[face] != default_face_set;
392 }))
393 {
395 node_changed[i] = true;
396 }
397 });
398 }
399 IndexMaskMemory memory;
400 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
401 attributes.remove(".sculpt_face_set");
402}
403
405{
406 const Scene &scene = *CTX_data_scene(C);
407 Object &object = *CTX_data_active_object(C);
409
410 const CreateMode mode = CreateMode(RNA_enum_get(op->ptr, "mode"));
411
412 const View3D *v3d = CTX_wm_view3d(C);
413 const Base *base = CTX_data_active_base(C);
414 if (!BKE_base_is_visible(v3d, base)) {
415 return OPERATOR_CANCELLED;
416 }
417
418 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
419 if (pbvh.type() == bke::pbvh::Type::BMesh) {
420 /* Dyntopo not supported. */
421 return OPERATOR_CANCELLED;
422 }
423
424 Mesh &mesh = *static_cast<Mesh *>(object.data);
425 const bke::AttributeAccessor attributes = mesh.attributes();
426
428
429 undo::push_begin(scene, object, op);
430
431 const int next_face_set = find_next_available_id(object);
432
433 IndexMaskMemory memory;
434 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
435 switch (mode) {
436 case CreateMode::Masked: {
437 if (pbvh.type() == bke::pbvh::Type::Mesh) {
438 const OffsetIndices faces = mesh.faces();
439 const Span<int> corner_verts = mesh.corner_verts();
440 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
442 const VArraySpan<float> mask = *attributes.lookup<float>(".sculpt_mask",
444 if (!mask.is_empty()) {
446 object,
447 node_mask,
448 [&](const Span<int> indices, MutableSpan<int> face_sets) {
449 for (const int i : indices.index_range()) {
450 if (!hide_poly.is_empty() && hide_poly[indices[i]]) {
451 continue;
452 }
453 const Span<int> face_verts = corner_verts.slice(faces[indices[i]]);
454 if (!std::any_of(face_verts.begin(),
455 face_verts.end(),
456 [&](const int vert) { return mask[vert] > 0.5f; }))
457 {
458 continue;
459 }
460 face_sets[i] = next_face_set;
461 }
462 });
463 }
464 }
465 else if (pbvh.type() == bke::pbvh::Type::Grids) {
466 const OffsetIndices<int> faces = mesh.faces();
467 const SculptSession &ss = *object.sculpt;
468 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
469 const int grid_area = subdiv_ccg.grid_area;
470 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
472 const Span<float> masks = subdiv_ccg.masks;
473 if (!masks.is_empty()) {
475 object,
476 node_mask,
477 [&](const Span<int> indices, MutableSpan<int> face_sets) {
478 for (const int i : indices.index_range()) {
479 if (!hide_poly.is_empty() && hide_poly[indices[i]]) {
480 continue;
481 }
482
483 const Span<float> face_masks = masks.slice(
484 bke::ccg::face_range(faces, grid_area, indices[i]));
485 if (!std::any_of(face_masks.begin(),
486 face_masks.end(),
487 [&](const float mask) { return mask > 0.5f; }))
488 {
489 continue;
490 }
491 face_sets[i] = next_face_set;
492 }
493 });
494 }
495 }
496 break;
497 }
498 case CreateMode::Visible: {
499 const VArray<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
500 switch (array_utils::booleans_mix_calc(hide_poly)) {
504 /* If all vertices in the sculpt are visible, remove face sets and update the default
505 * color. This way the new face set will be white, and it is a quick way of disabling all
506 * face sets and the performance hit of rendering the overlay. */
507 clear_face_sets(depsgraph, object, node_mask);
508 break;
510 const VArraySpan<bool> hide_poly_span(hide_poly);
512 object,
513 node_mask,
514 [&](const Span<int> indices, MutableSpan<int> face_sets) {
515 for (const int i : indices.index_range()) {
516 if (!hide_poly_span[indices[i]]) {
517 face_sets[i] = next_face_set;
518 }
519 }
520 });
521 break;
522 }
523 break;
524 }
525 case CreateMode::All: {
527 object,
528 node_mask,
529 [&](const Span<int> /*indices*/, MutableSpan<int> face_sets) {
530 face_sets.fill(next_face_set);
531 });
532 break;
533 }
535 const VArraySpan<bool> select_poly = *attributes.lookup_or_default<bool>(
536 ".select_poly", bke::AttrDomain::Face, false);
537 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
539
541 depsgraph, object, node_mask, [&](const Span<int> indices, MutableSpan<int> face_sets) {
542 for (const int i : indices.index_range()) {
543 if (select_poly[indices[i]]) {
544 if (!hide_poly.is_empty() && hide_poly[i]) {
545 continue;
546 }
547 face_sets[i] = next_face_set;
548 }
549 }
550 });
551
552 break;
553 }
554 }
555
556 undo::push_end(object);
557
559
560 return OPERATOR_FINISHED;
561}
562
564{
565 ot->name = "Create Face Set";
566 ot->idname = "SCULPT_OT_face_sets_create";
567 ot->description = "Create a new Face Set";
568
569 ot->exec = create_op_exec;
570 ot->poll = SCULPT_mode_poll;
571
573
574 static EnumPropertyItem modes[] = {
575 {int(CreateMode::Masked),
576 "MASKED",
577 0,
578 "Face Set from Masked",
579 "Create a new Face Set from the masked faces"},
581 "VISIBLE",
582 0,
583 "Face Set from Visible",
584 "Create a new Face Set from the visible vertices"},
585 {int(CreateMode::All),
586 "ALL",
587 0,
588 "Face Set Full Mesh",
589 "Create an unique Face Set with all faces in the sculpt"},
591 "SELECTION",
592 0,
593 "Face Set from Edit Mode Selection",
594 "Create an Face Set corresponding to the Edit Mode face selection"},
595 {0, nullptr, 0, nullptr, nullptr},
596 };
597 RNA_def_enum(ot->srna, "mode", modes, int(CreateMode::Masked), "Mode", "");
598}
599
610
611using FaceSetsFloodFillFn = FunctionRef<bool(int from_face, int edge, int to_face)>;
612
613static void init_flood_fill(Object &ob, const FaceSetsFloodFillFn &test_fn)
614{
615 SculptSession &ss = *ob.sculpt;
616 Mesh *mesh = static_cast<Mesh *>(ob.data);
617
618 BitVector<> visited_faces(mesh->faces_num, false);
619
621
622 const Span<int2> edges = mesh->edges();
623 const OffsetIndices faces = mesh->faces();
624 const Span<int> corner_edges = mesh->corner_edges();
625
626 if (ss.edge_to_face_map.is_empty()) {
628 faces, corner_edges, edges.size(), ss.edge_to_face_offsets, ss.edge_to_face_indices);
629 }
630
631 const bke::AttributeAccessor attributes = mesh->attributes();
632 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
633 const Set<int> hidden_face_sets = gather_hidden_face_sets(hide_poly, face_sets.span);
634
635 int next_face_set = 1;
636
637 for (const int i : faces.index_range()) {
638 if (!hide_poly.is_empty() && hide_poly[i]) {
639 continue;
640 }
641 if (visited_faces[i]) {
642 continue;
643 }
644 std::queue<int> queue;
645
646 while (hidden_face_sets.contains(next_face_set)) {
647 next_face_set += 1;
648 }
649 face_sets.span[i] = next_face_set;
650 visited_faces[i].set(true);
651 queue.push(i);
652
653 while (!queue.empty()) {
654 const int face_i = queue.front();
655 queue.pop();
656
657 for (const int edge_i : corner_edges.slice(faces[face_i])) {
658 for (const int neighbor_i : ss.edge_to_face_map[edge_i]) {
659 if (neighbor_i == face_i) {
660 continue;
661 }
662 if (visited_faces[neighbor_i]) {
663 continue;
664 }
665 if (!hide_poly.is_empty() && hide_poly[neighbor_i]) {
666 continue;
667 }
668 if (!test_fn(face_i, edge_i, neighbor_i)) {
669 continue;
670 }
671
672 face_sets.span[neighbor_i] = next_face_set;
673 visited_faces[neighbor_i].set(true);
674 queue.push(neighbor_i);
675 }
676 }
677 }
678
679 next_face_set += 1;
680 }
681
682 face_sets.finish();
683}
684
685Set<int> gather_hidden_face_sets(const Span<bool> hide_poly, const Span<int> face_sets)
686{
687 if (hide_poly.is_empty()) {
688 return {};
689 }
690
691 Set<int> hidden_face_sets;
692 for (const int i : hide_poly.index_range()) {
693 if (hide_poly[i]) {
694 hidden_face_sets.add(face_sets[i]);
695 }
696 }
697
698 return hidden_face_sets;
699}
700
702{
703 const Scene &scene = *CTX_data_scene(C);
706
707 const InitMode mode = InitMode(RNA_enum_get(op->ptr, "mode"));
708
709 const View3D *v3d = CTX_wm_view3d(C);
710 const Base *base = CTX_data_active_base(C);
711 if (!BKE_base_is_visible(v3d, base)) {
712 return OPERATOR_CANCELLED;
713 }
714
716
718 /* Dyntopo not supported. */
719 if (pbvh.type() == bke::pbvh::Type::BMesh) {
720 return OPERATOR_CANCELLED;
721 }
722
723 IndexMaskMemory memory;
724 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
725 if (node_mask.is_empty()) {
726 return OPERATOR_CANCELLED;
727 }
728
729 undo::push_begin(scene, ob, op);
731
732 const float threshold = RNA_float_get(op->ptr, "threshold");
733
734 Mesh *mesh = static_cast<Mesh *>(ob.data);
735 const bke::AttributeAccessor attributes = mesh->attributes();
736
737 switch (mode) {
739 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
740 ".hide_poly", bke::AttrDomain::Face, false);
741 init_flood_fill(ob, [&](const int from_face, const int /*edge*/, const int to_face) {
742 return hide_poly[from_face] == hide_poly[to_face];
743 });
744 break;
745 }
746 case InitMode::Materials: {
748 const VArraySpan<int> material_indices = *attributes.lookup_or_default<int>(
749 "material_index", bke::AttrDomain::Face, 0);
750 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
752 for (const int i : IndexRange(mesh->faces_num)) {
753 if (!hide_poly.is_empty() && hide_poly[i]) {
754 continue;
755 }
756
757 /* In some cases material face set index could be same as hidden face set index
758 * A more robust implementation is needed to avoid this */
759 face_sets.span[i] = material_indices[i] + 1;
760 }
761
762 face_sets.finish();
763 break;
764 }
765 case InitMode::Normals: {
766 const Span<float3> face_normals = mesh->face_normals();
767 init_flood_fill(ob, [&](const int from_face, const int /*edge*/, const int to_face) -> bool {
768 return std::abs(math::dot(face_normals[from_face], face_normals[to_face])) > threshold;
769 });
770 break;
771 }
772 case InitMode::UVSeams: {
773 const VArraySpan<bool> uv_seams = *mesh->attributes().lookup_or_default<bool>(
774 "uv_seam", bke::AttrDomain::Edge, false);
776 [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
777 return !uv_seams[edge];
778 });
779 break;
780 }
781 case InitMode::Creases: {
782 const VArraySpan<float> creases = *attributes.lookup_or_default<float>(
783 "crease_edge", bke::AttrDomain::Edge, 0.0f);
785 [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
786 return creases[edge] < threshold;
787 });
788 break;
789 }
791 const VArraySpan<bool> sharp_edges = *mesh->attributes().lookup_or_default<bool>(
792 "sharp_edge", bke::AttrDomain::Edge, false);
794 [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
795 return !sharp_edges[edge];
796 });
797 break;
798 }
800 const VArraySpan<float> bevel_weights = *attributes.lookup_or_default<float>(
801 "bevel_weight_edge", bke::AttrDomain::Edge, 0.0f);
803 [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
804 return bevel_weights[edge] < threshold;
805 });
806 break;
807 }
809 Array<int> face_sets_copy = duplicate_face_sets(*mesh);
810 init_flood_fill(ob, [&](const int from_face, const int /*edge*/, const int to_face) -> bool {
811 return face_sets_copy[from_face] == face_sets_copy[to_face];
812 });
813 break;
814 }
815 }
816
817 undo::push_end(ob);
818
819 pbvh.tag_face_sets_changed(node_mask);
820
822
823 return OPERATOR_FINISHED;
824}
825
827{
828 ot->name = "Init Face Sets";
829 ot->idname = "SCULPT_OT_face_sets_init";
830 ot->description = "Initializes all Face Sets in the mesh";
831
832 ot->exec = init_op_exec;
833 ot->poll = SCULPT_mode_poll;
834
836
837 static EnumPropertyItem modes[] = {
839 "LOOSE_PARTS",
840 0,
841 "Face Sets from Loose Parts",
842 "Create a Face Set per loose part in the mesh"},
844 "MATERIALS",
845 0,
846 "Face Sets from Material Slots",
847 "Create a Face Set per Material Slot"},
848 {int(InitMode::Normals),
849 "NORMALS",
850 0,
851 "Face Sets from Mesh Normals",
852 "Create Face Sets for Faces that have similar normal"},
853 {int(InitMode::UVSeams),
854 "UV_SEAMS",
855 0,
856 "Face Sets from UV Seams",
857 "Create Face Sets using UV Seams as boundaries"},
858 {int(InitMode::Creases),
859 "CREASES",
860 0,
861 "Face Sets from Edge Creases",
862 "Create Face Sets using Edge Creases as boundaries"},
864 "BEVEL_WEIGHT",
865 0,
866 "Face Sets from Bevel Weight",
867 "Create Face Sets using Bevel Weights as boundaries"},
869 "SHARP_EDGES",
870 0,
871 "Face Sets from Sharp Edges",
872 "Create Face Sets using Sharp Edges as boundaries"},
874 "FACE_SET_BOUNDARIES",
875 0,
876 "Face Sets from Face Set Boundaries",
877 "Create a Face Set per isolated Face Set"},
878 {0, nullptr, 0, nullptr, nullptr},
879 };
880 RNA_def_enum(ot->srna, "mode", modes, int(InitMode::LooseParts), "Mode", "");
882 ot->srna,
883 "threshold",
884 0.5f,
885 0.0f,
886 1.0f,
887 "Threshold",
888 "Minimum value to consider a certain attribute a boundary when creating the Face Sets",
889 0.0f,
890 1.0f);
891}
892
893enum class VisibilityMode {
897};
898
899static void face_hide_update(const Depsgraph &depsgraph,
900 Object &object,
901 const IndexMask &node_mask,
902 const FunctionRef<void(Span<int>, MutableSpan<bool>)> calc_hide)
903{
904 SculptSession &ss = *object.sculpt;
905 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
906 Mesh &mesh = *static_cast<Mesh *>(object.data);
907 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
909 ".hide_poly", bke::AttrDomain::Face);
910
911 struct TLS {
912 Vector<int> face_indices;
913 Vector<bool> new_hide;
914 };
915
916 Array<bool> node_changed(node_mask.min_array_size(), false);
917
919 if (pbvh.type() == bke::pbvh::Type::Mesh) {
921 node_mask.foreach_index(GrainSize(1), [&](const int i) {
922 TLS &tls = all_tls.local();
923 const Span<int> faces = nodes[i].faces();
924
925 tls.new_hide.resize(faces.size());
926 MutableSpan<bool> new_hide = tls.new_hide;
927 gather_data_mesh(hide_poly.span.as_span(), faces, new_hide);
928 calc_hide(faces, new_hide);
929 if (array_utils::indexed_data_equal<bool>(hide_poly.span, faces, new_hide)) {
930 return;
931 }
932
934 scatter_data_mesh(new_hide.as_span(), faces, hide_poly.span);
935 node_changed[i] = true;
936 });
937 }
938 else if (pbvh.type() == bke::pbvh::Type::Grids) {
940 node_mask.foreach_index(GrainSize(1), [&](const int i) {
941 TLS &tls = all_tls.local();
943 *ss.subdiv_ccg, nodes[i], tls.face_indices);
944
945 tls.new_hide.resize(faces.size());
946 MutableSpan<bool> new_hide = tls.new_hide;
947 gather_data_mesh(hide_poly.span.as_span(), faces, new_hide);
948 calc_hide(faces, new_hide);
949 if (array_utils::indexed_data_equal<bool>(hide_poly.span, faces, new_hide)) {
950 return;
951 }
952
954 scatter_data_mesh(new_hide.as_span(), faces, hide_poly.span);
955 node_changed[i] = true;
956 });
957 }
958
959 hide_poly.finish();
960
961 IndexMaskMemory memory;
962 const IndexMask changed_nodes = IndexMask::from_bools(node_changed, memory);
963 if (changed_nodes.is_empty()) {
964 return;
965 }
967 pbvh.tag_visibility_changed(node_mask);
968}
969
970static void show_all(Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
971{
972 switch (bke::object::pbvh_get(object)->type()) {
974 hide::mesh_show_all(depsgraph, object, node_mask);
975 break;
977 hide::grids_show_all(depsgraph, object, node_mask);
978 break;
981 break;
982 }
983}
984
986{
987 const Scene &scene = *CTX_data_scene(C);
988 Object &object = *CTX_data_active_object(C);
989 SculptSession &ss = *object.sculpt;
991
994
995 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
996
997 if (pbvh.type() == bke::pbvh::Type::BMesh) {
998 /* Not supported for dyntopo. There is no active face. */
999 return OPERATOR_CANCELLED;
1000 }
1001
1002 const VisibilityMode mode = VisibilityMode(RNA_enum_get(op->ptr, "mode"));
1003 const int active_face_set = active_face_set_get(object);
1004
1005 undo::push_begin(scene, object, op);
1006
1007 IndexMaskMemory memory;
1008 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1009
1010 const bke::AttributeAccessor attributes = mesh->attributes();
1011 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1012 const VArraySpan<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
1014
1015 switch (mode) {
1017 if (hide_poly.contains(true) || face_sets.is_empty()) {
1018 show_all(depsgraph, object, node_mask);
1019 }
1020 else {
1022 depsgraph, object, node_mask, [&](const Span<int> faces, MutableSpan<bool> hide) {
1023 for (const int i : hide.index_range()) {
1024 hide[i] = face_sets[faces[i]] != active_face_set;
1025 }
1026 });
1027 }
1028 break;
1029 }
1031 if (face_sets.is_empty()) {
1032 show_all(depsgraph, object, node_mask);
1033 }
1034 else {
1036 depsgraph, object, node_mask, [&](const Span<int> faces, MutableSpan<bool> hide) {
1037 for (const int i : hide.index_range()) {
1038 if (face_sets[faces[i]] == active_face_set) {
1039 hide[i] = false;
1040 }
1041 }
1042 });
1043 }
1044 break;
1046 if (face_sets.is_empty()) {
1048 depsgraph, object, node_mask, [&](const Span<int> /*faces*/, MutableSpan<bool> hide) {
1049 hide.fill(true);
1050 });
1051 }
1052 else {
1054 depsgraph, object, node_mask, [&](const Span<int> faces, MutableSpan<bool> hide) {
1055 for (const int i : hide.index_range()) {
1056 if (face_sets[faces[i]] == active_face_set) {
1057 hide[i] = true;
1058 }
1059 }
1060 });
1061 }
1062 break;
1063 }
1064
1065 /* For modes that use the cursor active vertex, update the rotation origin for viewport
1066 * navigation. */
1069 if (std::holds_alternative<std::monostate>(ss.active_vert())) {
1070 ups->last_stroke_valid = false;
1071 }
1072 else {
1073 float location[3];
1074 copy_v3_v3(location, ss.active_vert_position(depsgraph, object));
1075 mul_m4_v3(object.object_to_world().ptr(), location);
1076 copy_v3_v3(ups->average_stroke_accum, location);
1077 ups->average_stroke_counter = 1;
1078 ups->last_stroke_valid = true;
1079 }
1080 }
1081
1082 undo::push_end(object);
1083
1084 pbvh.update_visibility(object);
1085
1086 islands::invalidate(*object.sculpt);
1088
1089 return OPERATOR_FINISHED;
1090}
1091
1093{
1095
1096 const View3D *v3d = CTX_wm_view3d(C);
1097 const Base *base = CTX_data_active_base(C);
1098 if (!BKE_base_is_visible(v3d, base)) {
1099 return OPERATOR_CANCELLED;
1100 }
1101
1102 /* Update the active vertex and Face Set using the cursor position to avoid relying on the paint
1103 * cursor updates. */
1105 const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
1107 cursor_geometry_info_update(C, &cgi, mval_fl, false);
1108
1109 return change_visibility_exec(C, op);
1110}
1111
1113{
1114 ot->name = "Face Sets Visibility";
1115 ot->idname = "SCULPT_OT_face_set_change_visibility";
1116 ot->description = "Change the visibility of the Face Sets of the sculpt";
1117
1118 ot->exec = change_visibility_exec;
1119 ot->invoke = change_visibility_invoke;
1120 ot->poll = SCULPT_mode_poll;
1121
1123
1124 static EnumPropertyItem modes[] = {
1126 "TOGGLE",
1127 0,
1128 "Toggle Visibility",
1129 "Hide all Face Sets except for the active one"},
1131 "SHOW_ACTIVE",
1132 0,
1133 "Show Active Face Set",
1134 "Show Active Face Set"},
1136 "HIDE_ACTIVE",
1137 0,
1138 "Hide Active Face Sets",
1139 "Hide Active Face Sets"},
1140 {0, nullptr, 0, nullptr, nullptr},
1141 };
1142 RNA_def_enum(ot->srna, "mode", modes, int(VisibilityMode::Toggle), "Mode", "");
1143}
1144
1146{
1148
1149 const View3D *v3d = CTX_wm_view3d(C);
1150 const Base *base = CTX_data_active_base(C);
1151 if (!BKE_base_is_visible(v3d, base)) {
1152 return OPERATOR_CANCELLED;
1153 }
1154
1156
1157 /* Dyntopo not supported. */
1158 if (pbvh.type() == bke::pbvh::Type::BMesh) {
1159 return OPERATOR_CANCELLED;
1160 }
1161
1162 Mesh *mesh = static_cast<Mesh *>(ob.data);
1163 const bke::AttributeAccessor attributes = mesh->attributes();
1164
1165 if (!attributes.contains(".sculpt_face_set")) {
1166 return OPERATOR_CANCELLED;
1167 }
1168
1169 const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1170 const int random_index = clamp_i(mesh->faces_num * BLI_hash_int_01(mesh->face_sets_color_seed),
1171 0,
1172 max_ii(0, mesh->faces_num - 1));
1173 mesh->face_sets_color_default = face_sets[random_index];
1174
1175 mesh->face_sets_color_seed += 1;
1176
1177 IndexMaskMemory memory;
1178 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1179 pbvh.tag_face_sets_changed(node_mask);
1180
1182
1183 return OPERATOR_FINISHED;
1184}
1185
1187{
1188 ot->name = "Randomize Face Sets Colors";
1189 ot->idname = "SCULPT_OT_face_sets_randomize_colors";
1190 ot->description = "Generates a new set of random colors to render the Face Sets in the viewport";
1191
1192 ot->exec = randomize_colors_exec;
1193 ot->poll = SCULPT_mode_poll;
1194
1195 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1196}
1197
1205
1206static void edit_grow_shrink(const Depsgraph &depsgraph,
1207 const Scene &scene,
1208 Object &object,
1209 const EditMode mode,
1210 const int active_face_set_id,
1211 const bool modify_hidden,
1212 wmOperator *op)
1213{
1214 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1215 Mesh &mesh = *static_cast<Mesh *>(object.data);
1216 const OffsetIndices faces = mesh.faces();
1217 const Span<int> corner_verts = mesh.corner_verts();
1218 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1219 const bke::AttributeAccessor attributes = mesh.attributes();
1220
1221 BLI_assert(attributes.contains(".sculpt_face_set"));
1222
1223 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1224 Array<int> prev_face_sets = duplicate_face_sets(mesh);
1225
1226 undo::push_begin(scene, object, op);
1227
1228 IndexMaskMemory memory;
1229 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1231 depsgraph, object, node_mask, [&](const Span<int> indices, MutableSpan<int> face_sets) {
1232 for (const int i : indices.index_range()) {
1233 const int face = indices[i];
1234 if (!modify_hidden && !hide_poly.is_empty() && hide_poly[face]) {
1235 continue;
1236 }
1237 if (mode == EditMode::Grow) {
1238 for (const int vert : corner_verts.slice(faces[face])) {
1239 for (const int neighbor_face_index : vert_to_face_map[vert]) {
1240 if (neighbor_face_index == face) {
1241 continue;
1242 }
1243 if (prev_face_sets[neighbor_face_index] == active_face_set_id) {
1244 face_sets[i] = active_face_set_id;
1245 }
1246 }
1247 }
1248 }
1249 else {
1250 if (prev_face_sets[face] == active_face_set_id) {
1251 for (const int vert_i : corner_verts.slice(faces[face])) {
1252 for (const int neighbor_face_index : vert_to_face_map[vert_i]) {
1253 if (neighbor_face_index == face) {
1254 continue;
1255 }
1256 if (prev_face_sets[neighbor_face_index] != active_face_set_id) {
1257 face_sets[i] = prev_face_sets[neighbor_face_index];
1258 }
1259 }
1260 }
1261 }
1262 }
1263 }
1264 });
1265
1266 undo::push_end(object);
1267}
1268
1269static bool check_single_face_set(const Object &object, const bool check_visible_only)
1270{
1271 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1272 const bke::AttributeAccessor attributes = mesh.attributes();
1273 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1274 const VArraySpan<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
1276
1277 if (face_sets.is_empty()) {
1278 return true;
1279 }
1280 int first_face_set = SCULPT_FACE_SET_NONE;
1281 if (check_visible_only) {
1282 for (const int i : face_sets.index_range()) {
1283 if (!hide_poly.is_empty() && hide_poly[i]) {
1284 continue;
1285 }
1286 first_face_set = face_sets[i];
1287 break;
1288 }
1289 }
1290 else {
1291 first_face_set = face_sets[0];
1292 }
1293
1294 if (first_face_set == SCULPT_FACE_SET_NONE) {
1295 return true;
1296 }
1297
1298 for (const int i : face_sets.index_range()) {
1299 if (check_visible_only && !hide_poly.is_empty() && hide_poly[i]) {
1300 continue;
1301 }
1302 if (face_sets[i] != first_face_set) {
1303 return false;
1304 }
1305 }
1306 return true;
1307}
1308
1309static void delete_geometry(Object &ob, const int active_face_set_id, const bool modify_hidden)
1310{
1311 Mesh &mesh = *static_cast<Mesh *>(ob.data);
1312 const bke::AttributeAccessor attributes = mesh.attributes();
1313 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1314 const VArraySpan<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
1316
1317 const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&mesh);
1318 BMeshCreateParams create_params{};
1319 create_params.use_toolflags = true;
1320 BMesh *bm = BM_mesh_create(&allocsize, &create_params);
1321
1322 BMeshFromMeshParams convert_params{};
1323 convert_params.calc_vert_normal = true;
1324 convert_params.calc_face_normal = true;
1325 BM_mesh_bm_from_me(bm, &mesh, &convert_params);
1326
1330 BMIter iter;
1331 BMFace *f;
1332 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1333 const int face_index = BM_elem_index_get(f);
1334 if (!modify_hidden && !hide_poly.is_empty() && hide_poly[face_index]) {
1335 continue;
1336 }
1337 BM_elem_flag_set(f, BM_ELEM_TAG, face_sets[face_index] == active_face_set_id);
1338 }
1341
1342 BMeshToMeshParams bmesh_to_mesh_params{};
1343 bmesh_to_mesh_params.calc_object_remap = false;
1344 BM_mesh_bm_to_me(nullptr, bm, &mesh, &bmesh_to_mesh_params);
1345
1347}
1348
1349static void edit_fairing(const Depsgraph &depsgraph,
1350 const Sculpt &sd,
1351 Object &ob,
1352 const int active_face_set_id,
1353 const eMeshFairingDepth fair_order,
1354 const float strength)
1355{
1356 SculptSession &ss = *ob.sculpt;
1357 Mesh &mesh = *static_cast<Mesh *>(ob.data);
1360
1361 const PositionDeformData position_data(depsgraph, ob);
1362 const Span<float3> positions = position_data.eval;
1363 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1364 const BitSpan boundary_verts = ss.vertex_info.boundary;
1365 const bke::AttributeAccessor attributes = mesh.attributes();
1366 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1367 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1368
1369 Array<bool> fair_verts(positions.size(), false);
1370 for (const int vert : positions.index_range()) {
1371 if (boundary::vert_is_boundary(vert_to_face_map, hide_poly, boundary_verts, vert)) {
1372 continue;
1373 }
1374 if (!vert_has_face_set(vert_to_face_map, face_sets, vert, active_face_set_id)) {
1375 continue;
1376 }
1377 if (!vert_has_unique_face_set(vert_to_face_map, face_sets, vert)) {
1378 continue;
1379 }
1380 fair_verts[vert] = true;
1381 }
1382
1383 Array<float3> new_positions = positions;
1384 BKE_mesh_prefair_and_fair_verts(&mesh, new_positions, fair_verts.data(), fair_order);
1385
1386 struct LocalData {
1387 Vector<float3> translations;
1388 };
1389
1390 IndexMaskMemory memory;
1391 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1393
1395 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1396 LocalData &tls = all_tls.local();
1397 const Span<int> verts = nodes[i].verts();
1398 tls.translations.resize(verts.size());
1399 const MutableSpan<float3> translations = tls.translations;
1400 for (const int i : verts.index_range()) {
1401 translations[i] = new_positions[verts[i]] - positions[verts[i]];
1402 }
1403 scale_translations(translations, strength);
1404 clip_and_lock_translations(sd, ss, positions, verts, translations);
1405 position_data.deform(translations, verts);
1406 });
1407}
1408
1409static bool edit_is_operation_valid(const Object &object,
1410 const EditMode mode,
1411 const bool modify_hidden)
1412{
1413 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1414 if (pbvh.type() == bke::pbvh::Type::BMesh) {
1415 /* Dyntopo is not supported. */
1416 return false;
1417 }
1418
1419 if (mode == EditMode::DeleteGeometry) {
1420 if (pbvh.type() == bke::pbvh::Type::Grids) {
1421 /* Modification of base mesh geometry requires special remapping of multi-resolution
1422 * displacement, which does not happen here.
1423 * Disable delete operation. It can be supported in the future by doing similar displacement
1424 * data remapping as what happens in the mesh edit mode. */
1425 return false;
1426 }
1427 if (check_single_face_set(object, !modify_hidden)) {
1428 /* Cancel the operator if the mesh only contains one Face Set to avoid deleting the
1429 * entire object. */
1430 return false;
1431 }
1432 }
1433
1435 if (pbvh.type() == bke::pbvh::Type::Grids) {
1436 /* TODO: Multi-resolution topology representation using grids and duplicates can't be used
1437 * directly by the fair algorithm. Multi-resolution topology needs to be exposed in a
1438 * different way or converted to a mesh for this operation. */
1439 return false;
1440 }
1441 }
1442
1443 if (ELEM(mode, EditMode::Grow, EditMode::Shrink)) {
1444 if (pbvh.type() == bke::pbvh::Type::Mesh) {
1445 const Mesh &mesh = *static_cast<Mesh *>(object.data);
1446 const bke::AttributeAccessor attributes = mesh.attributes();
1447 if (!attributes.contains(".sculpt_face_set")) {
1448 /* If a mesh does not have the face set attribute, growing or shrinking the face set will
1449 * have no effect, exit early in this case. */
1450 return false;
1451 }
1452 }
1453 }
1454
1455 return true;
1456}
1457
1459 bContext *C, Object &ob, const int active_face_set, const bool modify_hidden, wmOperator *op)
1460{
1461 const Scene &scene = *CTX_data_scene(C);
1462 Mesh *mesh = static_cast<Mesh *>(ob.data);
1463 undo::geometry_begin(scene, ob, op);
1464 delete_geometry(ob, active_face_set, modify_hidden);
1470}
1471
1473 bContext *C, Object &ob, const int active_face_set, const EditMode mode, wmOperator *op)
1474{
1475 const Scene &scene = *CTX_data_scene(C);
1476 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1477 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
1479 IndexMaskMemory memory;
1480 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1481
1482 const float strength = RNA_float_get(op->ptr, "strength");
1483
1484 undo::push_begin(scene, ob, op);
1486
1487 switch (mode) {
1489 edit_fairing(depsgraph, sd, ob, active_face_set, MESH_FAIRING_DEPTH_POSITION, strength);
1490 break;
1492 edit_fairing(depsgraph, sd, ob, active_face_set, MESH_FAIRING_DEPTH_TANGENCY, strength);
1493 break;
1494 default:
1496 }
1497
1498 pbvh.tag_positions_changed(node_mask);
1499 pbvh.update_bounds(depsgraph, ob);
1502 undo::push_end(ob);
1503}
1504
1506{
1509 const EditMode mode = EditMode(RNA_enum_get(op->ptr, "mode"));
1510 const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden");
1511
1512 if (!edit_is_operation_valid(*ob, mode, modify_hidden)) {
1513 return false;
1514 }
1515
1517
1518 return true;
1519}
1520
1522{
1523 if (!edit_op_init(C, op)) {
1524 return OPERATOR_CANCELLED;
1525 }
1526
1527 const Scene &scene = *CTX_data_scene(C);
1528 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1530
1531 const int active_face_set = RNA_int_get(op->ptr, "active_face_set");
1532 const EditMode mode = EditMode(RNA_enum_get(op->ptr, "mode"));
1533 const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden");
1534
1535 switch (mode) {
1537 edit_modify_geometry(C, ob, active_face_set, modify_hidden, op);
1538 break;
1539 case EditMode::Grow:
1540 case EditMode::Shrink:
1541 edit_grow_shrink(depsgraph, scene, ob, mode, active_face_set, modify_hidden, op);
1542 break;
1545 edit_modify_coordinates(C, ob, active_face_set, mode, op);
1546 break;
1547 }
1548
1550
1551 return OPERATOR_FINISHED;
1552}
1553
1555{
1558
1559 const View3D *v3d = CTX_wm_view3d(C);
1560 const Base *base = CTX_data_active_base(C);
1561 if (!BKE_base_is_visible(v3d, base)) {
1562 return OPERATOR_CANCELLED;
1563 }
1564
1566
1567 /* Update the current active Face Set and Vertex as the operator can be used directly from the
1568 * tool without brush cursor. */
1570 const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
1571 if (!cursor_geometry_info_update(C, &cgi, mval_fl, false)) {
1572 /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */
1573 return OPERATOR_CANCELLED;
1574 }
1575 RNA_int_set(op->ptr, "active_face_set", active_face_set_get(ob));
1576
1577 return edit_op_exec(C, op);
1578}
1579
1581{
1582 ot->name = "Edit Face Set";
1583 ot->idname = "SCULPT_OT_face_set_edit";
1584 ot->description = "Edits the current active Face Set";
1585
1586 ot->invoke = edit_op_invoke;
1587 ot->exec = edit_op_exec;
1588 ot->poll = SCULPT_mode_poll;
1589
1591
1592 PropertyRNA *prop = RNA_def_int(
1593 ot->srna, "active_face_set", 1, 0, INT_MAX, "Active Face Set", "", 0, 64);
1595
1596 static EnumPropertyItem modes[] = {
1597 {int(EditMode::Grow),
1598 "GROW",
1599 0,
1600 "Grow Face Set",
1601 "Grows the Face Sets boundary by one face based on mesh topology"},
1602 {int(EditMode::Shrink),
1603 "SHRINK",
1604 0,
1605 "Shrink Face Set",
1606 "Shrinks the Face Sets boundary by one face based on mesh topology"},
1608 "DELETE_GEOMETRY",
1609 0,
1610 "Delete Geometry",
1611 "Deletes the faces that are assigned to the Face Set"},
1613 "FAIR_POSITIONS",
1614 0,
1615 "Fair Positions",
1616 "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
1617 "vertex positions"},
1619 "FAIR_TANGENCY",
1620 0,
1621 "Fair Tangency",
1622 "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
1623 "vertex tangents"},
1624 {0, nullptr, 0, nullptr, nullptr},
1625 };
1626 RNA_def_enum(ot->srna, "mode", modes, int(EditMode::Grow), "Mode", "");
1627 prop = RNA_def_float(ot->srna, "strength", 1.0f, 0.0f, 1.0f, "Strength", "", 0.0f, 1.0f);
1629
1630 ot->prop = RNA_def_boolean(ot->srna,
1631 "modify_hidden",
1632 false,
1633 "Modify Hidden",
1634 "Apply the edit operation to hidden geometry");
1635}
1636
1638
1639/* -------------------------------------------------------------------- */
1643
1649
1650static void gesture_begin(bContext &C, wmOperator &op, gesture::GestureData &gesture_data)
1651{
1652 const Scene &scene = *CTX_data_scene(&C);
1653 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C);
1655 undo::push_begin(scene, *gesture_data.vc.obact, &op);
1656}
1657
1658static void gesture_apply_mesh(gesture::GestureData &gesture_data, const IndexMask &node_mask)
1659{
1660 FaceSetOperation *face_set_operation = (FaceSetOperation *)gesture_data.operation;
1661 const int new_face_set = face_set_operation->new_face_set_id;
1662 const Depsgraph &depsgraph = *gesture_data.vc.depsgraph;
1663 Object &object = *gesture_data.vc.obact;
1664 Mesh &mesh = *static_cast<Mesh *>(object.data);
1665 bke::AttributeAccessor attributes = mesh.attributes();
1666 SculptSession &ss = *gesture_data.ss;
1667 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1668
1669 const Span<float3> positions = bke::pbvh::vert_positions_eval(depsgraph, object);
1670 const OffsetIndices<int> faces = mesh.faces();
1671 const Span<int> corner_verts = mesh.corner_verts();
1672 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1674
1675 struct TLS {
1676 Vector<int> face_indices;
1677 };
1678
1679 Array<bool> node_changed(pbvh.nodes_num(), false);
1680
1682 if (pbvh.type() == bke::pbvh::Type::Mesh) {
1684 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1686 bool any_updated = false;
1687 for (const int face : nodes[i].faces()) {
1688 if (!hide_poly.is_empty() && hide_poly[face]) {
1689 continue;
1690 }
1691 const Span<int> face_verts = corner_verts.slice(faces[face]);
1692 const float3 face_center = bke::mesh::face_center_calc(positions, face_verts);
1693 const float3 face_normal = bke::mesh::face_normal_calc(positions, face_verts);
1694 if (!gesture::is_affected(gesture_data, face_center, face_normal)) {
1695 continue;
1696 }
1697 face_sets.span[face] = new_face_set;
1698 any_updated = true;
1699 }
1700 if (any_updated) {
1701 node_changed[i] = true;
1702 }
1703 });
1704 }
1705 else if (pbvh.type() == bke::pbvh::Type::Grids) {
1707 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1708 TLS &tls = all_tls.local();
1711 *ss.subdiv_ccg, nodes[i], tls.face_indices);
1712
1713 bool any_updated = false;
1714 for (const int face : node_faces) {
1715 if (!hide_poly.is_empty() && hide_poly[face]) {
1716 continue;
1717 }
1718 const Span<int> face_verts = corner_verts.slice(faces[face]);
1719 const float3 face_center = bke::mesh::face_center_calc(positions, face_verts);
1720 const float3 face_normal = bke::mesh::face_normal_calc(positions, face_verts);
1721 if (!gesture::is_affected(gesture_data, face_center, face_normal)) {
1722 continue;
1723 }
1724 face_sets.span[face] = new_face_set;
1725 any_updated = true;
1726 }
1727 if (any_updated) {
1728 node_changed[i] = true;
1729 }
1730 });
1731 }
1732
1733 IndexMaskMemory memory;
1734 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
1735 face_sets.finish();
1736}
1737
1738static void gesture_apply_bmesh(gesture::GestureData &gesture_data, const IndexMask &node_mask)
1739{
1740 FaceSetOperation *face_set_operation = (FaceSetOperation *)gesture_data.operation;
1741 const Depsgraph &depsgraph = *gesture_data.vc.depsgraph;
1742 const int new_face_set = face_set_operation->new_face_set_id;
1743 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(*gesture_data.vc.obact);
1745 const int offset = face_set::ensure_face_sets_bmesh(*gesture_data.vc.obact);
1746
1747 Array<bool> node_changed(node_mask.min_array_size(), false);
1748
1749 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1751
1752 bool any_updated = false;
1753 for (BMFace *face : BKE_pbvh_bmesh_node_faces(&nodes[i])) {
1754 if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
1755 continue;
1756 }
1757 float3 center;
1758 BM_face_calc_center_median(face, center);
1759 if (!gesture::is_affected(gesture_data, center, face->no)) {
1760 continue;
1761 }
1762 BM_ELEM_CD_SET_INT(face, offset, new_face_set);
1763 any_updated = true;
1764 }
1765
1766 if (any_updated) {
1767 node_changed[i] = true;
1768 }
1769 });
1770
1771 IndexMaskMemory memory;
1772 const IndexMask changed_nodes = IndexMask::from_bools(node_changed, memory);
1773 if (changed_nodes.is_empty()) {
1774 return;
1775 }
1776 pbvh.tag_face_sets_changed(node_mask);
1777}
1778
1780{
1781 switch (bke::object::pbvh_get(*gesture_data.vc.obact)->type()) {
1784 gesture_apply_mesh(gesture_data, gesture_data.node_mask);
1785 break;
1787 gesture_apply_bmesh(gesture_data, gesture_data.node_mask);
1788 break;
1789 }
1790}
1791
1792static void gesture_end(bContext & /*C*/, gesture::GestureData &gesture_data)
1793{
1794 undo::push_end(*gesture_data.vc.obact);
1795}
1796
1797static void init_operation(gesture::GestureData &gesture_data, wmOperator & /*op*/)
1798{
1799 Object &object = *gesture_data.vc.obact;
1800 gesture_data.operation = reinterpret_cast<gesture::Operation *>(
1802
1803 FaceSetOperation *face_set_operation = (FaceSetOperation *)gesture_data.operation;
1804
1805 face_set_operation->op.begin = gesture_begin;
1807 face_set_operation->op.end = gesture_end;
1808
1809 face_set_operation->new_face_set_id = face_set::find_next_available_id(object);
1810}
1811
1813{
1814 const View3D *v3d = CTX_wm_view3d(C);
1815 const Base *base = CTX_data_active_base(C);
1816 if (!BKE_base_is_visible(v3d, base)) {
1817 return OPERATOR_CANCELLED;
1818 }
1819
1820 return WM_gesture_box_invoke(C, op, event);
1821}
1822
1824{
1825 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_box(C, op);
1826 if (!gesture_data) {
1827 return OPERATOR_CANCELLED;
1828 }
1829 init_operation(*gesture_data, *op);
1830 gesture::apply(*C, *gesture_data, *op);
1831 return OPERATOR_FINISHED;
1832}
1833
1835{
1836 const View3D *v3d = CTX_wm_view3d(C);
1837 const Base *base = CTX_data_active_base(C);
1838 if (!BKE_base_is_visible(v3d, base)) {
1839 return OPERATOR_CANCELLED;
1840 }
1841
1842 return WM_gesture_lasso_invoke(C, op, event);
1843}
1844
1846{
1847 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_lasso(C, op);
1848 if (!gesture_data) {
1849 return OPERATOR_CANCELLED;
1850 }
1851 init_operation(*gesture_data, *op);
1852 gesture::apply(*C, *gesture_data, *op);
1853 return OPERATOR_FINISHED;
1854}
1855
1857{
1858 const View3D *v3d = CTX_wm_view3d(C);
1859 const Base *base = CTX_data_active_base(C);
1860 if (!BKE_base_is_visible(v3d, base)) {
1861 return OPERATOR_CANCELLED;
1862 }
1863
1865}
1866
1868{
1869 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_line(C, op);
1870 if (!gesture_data) {
1871 return OPERATOR_CANCELLED;
1872 }
1873 init_operation(*gesture_data, *op);
1874 gesture::apply(*C, *gesture_data, *op);
1875 return OPERATOR_FINISHED;
1876}
1877
1879{
1880 const View3D *v3d = CTX_wm_view3d(C);
1881 const Base *base = CTX_data_active_base(C);
1882 if (!BKE_base_is_visible(v3d, base)) {
1883 return OPERATOR_CANCELLED;
1884 }
1885
1886 return WM_gesture_polyline_invoke(C, op, event);
1887}
1888
1890{
1891 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_polyline(C, op);
1892 if (!gesture_data) {
1893 return OPERATOR_CANCELLED;
1894 }
1895 init_operation(*gesture_data, *op);
1896 gesture::apply(*C, *gesture_data, *op);
1897 return OPERATOR_FINISHED;
1898}
1899
1901{
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";
1905
1906 ot->invoke = gesture_polyline_invoke;
1908 ot->exec = gesture_polyline_exec;
1909
1911
1913
1916}
1917
1919{
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";
1923
1924 ot->invoke = gesture_box_invoke;
1925 ot->modal = WM_gesture_box_modal;
1926 ot->exec = gesture_box_exec;
1927
1929
1930 ot->flag = OPTYPE_REGISTER;
1931
1934}
1935
1937{
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";
1941
1942 ot->invoke = gesture_lasso_invoke;
1943 ot->modal = WM_gesture_lasso_modal;
1944 ot->exec = gesture_lasso_exec;
1945
1947
1949
1952}
1953
1955{
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";
1959
1960 ot->invoke = gesture_line_invoke;
1962 ot->exec = gesture_line_exec;
1963
1965
1966 ot->flag = OPTYPE_REGISTER;
1967
1970}
1971
1972
1973} // namespace blender::ed::sculpt_paint::face_set
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:77
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
Definition BKE_mesh.h:38
eMeshFairingDepth
@ 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
Definition BKE_paint.hh:344
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2657
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2146
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()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition BLI_hash.h:92
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 ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define BLT_I18NCONTEXT_AMOUNT
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ CD_PROP_INT32
Object is a sort of wrapper for general info.
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
Read Guarded memory(de)allocation.
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:390
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
@ BM_ELEM_HIDDEN
@ BM_ELEM_TAG
#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 StringRef name)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
BMesh const char void * data
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)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
BPy_StructRNA * depsgraph
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
const T * data() const
Definition BLI_array.hh:301
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const T * begin() const
Definition BLI_span.hh:220
constexpr bool is_empty() const
Definition BLI_span.hh:260
constexpr bool contains(const T &value) const
Definition BLI_span.hh:277
static VArray ForSingle(T value, const int64_t size)
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:559
Span< NodeT > nodes() const
void update_bounds(const Depsgraph &depsgraph, const Object &object)
Definition pbvh.cc:1202
int nodes_num() const
Definition pbvh.cc:514
void tag_face_sets_changed(const IndexMask &node_mask)
Definition pbvh.cc:586
void tag_visibility_changed(const IndexMask &node_mask)
Definition pbvh.cc:570
void update_visibility(const Object &object)
Definition pbvh.cc:1395
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7445
void foreach_index(Fn &&fn) const
static ushort indices[]
static float verts[][3]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
static char faces[256]
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
bool indexed_data_equal(const Span< T > all_values, const Span< int > indices, const Span< T > values)
BooleanMix booleans_mix_calc(const VArray< bool > &varray, IndexRange range_to_check)
IndexRange face_range(const OffsetIndices< int > faces, const int grid_area, const int face)
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
GroupedSpan< int > build_edge_to_face_map(OffsetIndices< int > faces, Span< int > corner_edges, int edges_num, Array< int > &r_offsets, Array< int > &r_indices)
float3 face_center_calc(Span< float3 > vert_positions, Span< int > face_verts)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
Span< int > node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg, const GridsNode &node, Vector< int > &faces)
Definition pbvh.cc:1583
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2416
bool vert_is_boundary(const GroupedSpan< int > vert_to_face_map, const Span< bool > hide_poly, const BitSpan boundary, const int vert)
Definition sculpt.cc:484
void ensure_boundary_info(Object &object)
Definition sculpt.cc:6059
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)
static void gesture_apply_for_symmetry_pass(bContext &, gesture::GestureData &gesture_data)
static wmOperatorStatus init_op_exec(bContext *C, wmOperator *op)
static wmOperatorStatus gesture_box_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus gesture_line_exec(bContext *C, wmOperator *op)
static wmOperatorStatus change_visibility_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)
Definition sculpt.cc:293
bool vert_has_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert, const int face_set)
Definition sculpt.cc:253
void SCULPT_OT_face_set_lasso_gesture(wmOperatorType *ot)
static void gesture_begin(bContext &C, wmOperator &op, gesture::GestureData &gesture_data)
void initialize_none_to_id(Mesh *mesh, int new_id)
static bool edit_op_init(bContext *C, wmOperator *op)
static wmOperatorStatus randomize_colors_exec(bContext *C, wmOperator *)
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)
static wmOperatorStatus change_visibility_exec(bContext *C, wmOperator *op)
void SCULPT_OT_face_sets_init(wmOperatorType *ot)
int active_update_and_get(bContext *C, Object &ob, const float mval_fl[2])
static wmOperatorStatus gesture_lasso_exec(bContext *C, wmOperator *op)
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)
static wmOperatorStatus edit_op_exec(bContext *C, 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)
static wmOperatorStatus gesture_polyline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
FunctionRef< bool(int from_face, int edge, int to_face)> FaceSetsFloodFillFn
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 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)
void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
static bool check_single_face_set(const Object &object, const bool check_visible_only)
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 wmOperatorStatus gesture_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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 wmOperatorStatus create_op_exec(bContext *C, wmOperator *op)
static void init_operation(gesture::GestureData &gesture_data, wmOperator &)
static wmOperatorStatus edit_op_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void SCULPT_OT_face_set_box_gesture(wmOperatorType *ot)
static void edit_modify_coordinates(bContext *C, Object &ob, const int active_face_set, const EditMode mode, wmOperator *op)
static wmOperatorStatus gesture_polyline_exec(bContext *C, wmOperator *op)
static void init_flood_fill(Object &ob, const FaceSetsFloodFillFn &test_fn)
static wmOperatorStatus gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int active_face_set_get(const Object &object)
Definition sculpt.cc:197
static void edit_modify_geometry(bContext *C, Object &ob, const int active_face_set, const bool modify_hidden, wmOperator *op)
std::unique_ptr< GestureData > init_from_box(bContext *C, wmOperator *op)
void operator_properties(wmOperatorType *ot, ShapeType shapeType)
std::unique_ptr< GestureData > init_from_polyline(bContext *C, wmOperator *op)
std::unique_ptr< GestureData > init_from_line(bContext *C, const wmOperator *op)
void apply(bContext &C, GestureData &gesture_data, wmOperator &op)
std::unique_ptr< GestureData > init_from_lasso(bContext *C, wmOperator *op)
bool is_affected(const GestureData &gesture_data, const float3 &position, const float3 &normal)
void tag_update_visibility(const bContext &C)
void grids_show_all(Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
void mesh_show_all(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
void sync_all_from_faces(Object &object)
Definition paint_hide.cc:57
void invalidate(SculptSession &ss)
Definition sculpt.cc:6185
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, const Type type)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:142
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7487
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7318
bool cursor_geometry_info_update(bContext *C, CursorGeometryInfo *out, const float2 &mval, const bool use_sampled_normal)
Definition sculpt.cc:4664
void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
Definition sculpt.cc:5131
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6421
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6381
void flush_update_step(const bContext *C, const UpdateType update_type)
Definition sculpt.cc:5083
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)
Definition BLI_task.hh:151
VecBase< float, 3 > float3
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_translation_context(PropertyRNA *prop, const char *context)
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_mode_poll_view3d(bContext *C)
Definition sculpt.cc:3666
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3660
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:760
BMHeader head
void * data
int grid_size
Definition BKE_ccg.hh:33
int grid_area
Definition BKE_ccg.hh:35
struct SculptSession * sculpt
SculptVertexInfo vertex_info
Definition BKE_paint.hh:482
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
ActiveVert active_vert() const
Definition paint.cc:2227
blender::Array< int > edge_to_face_offsets
Definition BKE_paint.hh:400
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2263
blender::GroupedSpan< int > edge_to_face_map
Definition BKE_paint.hh:402
blender::Array< int > edge_to_face_indices
Definition BKE_paint.hh:401
blender::BitVector boundary
Definition BKE_paint.hh:354
blender::Array< float > masks
struct UnifiedPaintSettings unified_paint_settings
Object * obact
Definition ED_view3d.hh:75
Depsgraph * depsgraph
Definition ED_view3d.hh:72
void(* end)(bContext &, GestureData &)
void(* begin)(bContext &, wmOperator &, GestureData &)
void(* apply_for_symmetry_pass)(bContext &, GestureData &)
int mval[2]
Definition WM_types.hh:760
struct PointerRNA * ptr
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
wmOperatorStatus WM_gesture_polyline_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_polyline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_straightline_oneshot_modal(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)