Blender V4.3
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.h"
28#include "BLI_task.hh"
29#include "BLI_vector.hh"
30
32#include "DNA_object_types.h"
33#include "DNA_scene_types.h"
34
35#include "BKE_attribute.hh"
36#include "BKE_ccg.hh"
37#include "BKE_context.hh"
38#include "BKE_customdata.hh"
39#include "BKE_layer.hh"
40#include "BKE_mesh.hh"
41#include "BKE_mesh_fair.hh"
42#include "BKE_mesh_mapping.hh"
43#include "BKE_object.hh"
44#include "BKE_paint.hh"
45#include "BKE_pbvh_api.hh"
46#include "BKE_subdiv_ccg.hh"
47
48#include "DEG_depsgraph.hh"
49
50#include "WM_api.hh"
51#include "WM_types.hh"
52
53#include "ED_sculpt.hh"
54
55#include "mesh_brush_common.hh"
56#include "paint_hide.hh"
57#include "sculpt_automask.hh"
58#include "sculpt_boundary.hh"
59#include "sculpt_gesture.hh"
60#include "sculpt_intern.hh"
61#include "sculpt_islands.hh"
62#include "sculpt_undo.hh"
63
64#include "RNA_access.hh"
65#include "RNA_define.hh"
66
67#include "bmesh.hh"
68
70
71/* -------------------------------------------------------------------- */
74
76{
77 SculptSession &ss = *object.sculpt;
78 switch (bke::object::pbvh_get(object)->type()) {
81 Mesh &mesh = *static_cast<Mesh *>(object.data);
82 const bke::AttributeAccessor attributes = mesh.attributes();
83 const VArraySpan<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
86 face_sets.index_range(),
87 4096,
88 1,
89 [&](const IndexRange range, int max) {
90 for (const int id : face_sets.slice(range)) {
91 max = std::max(max, id);
92 }
93 return max;
94 },
95 [](const int a, const int b) { return std::max(a, b); });
96 return max + 1;
97 }
99 BMesh &bm = *ss.bm;
100 const int cd_offset = CustomData_get_offset_named(
101 &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
102 if (cd_offset == -1) {
103 return 1;
104 }
105 int next_face_set = 1;
106 BMIter iter;
107 BMFace *f;
108 BM_ITER_MESH (f, &iter, &bm, BM_FACES_OF_MESH) {
109 const int fset = *static_cast<const int *>(POINTER_OFFSET(f->head.data, cd_offset));
110 next_face_set = std::max(next_face_set, fset);
111 }
112
113 return next_face_set + 1;
114 }
115 }
117 return 0;
118}
119
120void initialize_none_to_id(Mesh *mesh, const int new_id)
121{
122 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
123 bke::SpanAttributeWriter<int> face_sets = attributes.lookup_for_write_span<int>(
124 ".sculpt_face_set");
125 if (!face_sets) {
126 return;
127 }
128
129 for (const int i : face_sets.span.index_range()) {
130 if (face_sets.span[i] == SCULPT_FACE_SET_NONE) {
131 face_sets.span[i] = new_id;
132 }
133 }
134 face_sets.finish();
135}
136
137int active_update_and_get(bContext *C, Object &ob, const float mval[2])
138{
139 if (!ob.sculpt) {
141 }
142
144 if (!SCULPT_cursor_geometry_info_update(C, &gi, mval, false)) {
146 }
147
148 return active_face_set_get(ob);
149}
150
152{
153 Mesh &mesh = *static_cast<Mesh *>(object.data);
154 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
155 if (attributes.contains(".sculpt_face_set")) {
156 return false;
157 }
158 attributes.add<int>(".sculpt_face_set",
161 mesh.face_sets_color_default = 1;
162 return true;
163}
164
166{
167 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
168 if (!attributes.contains(".sculpt_face_set")) {
169 attributes.add<int>(".sculpt_face_set",
172 mesh.face_sets_color_default = 1;
173 }
174 return attributes.lookup_or_add_for_write_span<int>(".sculpt_face_set", bke::AttrDomain::Face);
175}
176
178{
179 Mesh &mesh = *static_cast<Mesh *>(object.data);
180 SculptSession &ss = *object.sculpt;
181 BMesh &bm = *ss.bm;
182 if (!CustomData_has_layer_named(&bm.pdata, CD_PROP_INT32, ".sculpt_face_set")) {
183 BM_data_layer_add_named(&bm, &bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
184 const int offset = CustomData_get_offset_named(&bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
185 if (offset == -1) {
186 return -1;
187 }
188 BMIter iter;
189 BMFace *face;
190 BM_ITER_MESH (face, &iter, &bm, BM_FACES_OF_MESH) {
191 BM_ELEM_CD_SET_INT(face, offset, 1);
192 }
193 mesh.face_sets_color_default = 1;
194 return offset;
195 }
196 return CustomData_get_offset_named(&bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
197}
198
200{
201 const bke::AttributeAccessor attributes = mesh.attributes();
202 const VArray<int> attribute = *attributes.lookup_or_default(
203 ".sculpt_face_set", bke::AttrDomain::Face, 0);
204 Array<int> face_sets(attribute.size());
206 return face_sets;
207}
208
210 const Span<int> face_sets,
211 const bool unique,
212 const Span<int> verts,
213 const MutableSpan<float> factors)
214{
215 BLI_assert(verts.size() == factors.size());
216
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])) {
219 factors[i] = 0.0f;
220 }
221 }
222}
223
225 const Span<int> corner_verts,
226 const GroupedSpan<int> vert_to_face_map,
227 const Span<int> face_sets,
228 const SubdivCCG &subdiv_ccg,
229 const bool unique,
230 const Span<int> grids,
231 const MutableSpan<float> factors)
232{
233 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
234 BLI_assert(grids.size() * key.grid_area == factors.size());
235
236 for (const int i : grids.index_range()) {
237 const int node_start = i * key.grid_area;
238 for (const int y : IndexRange(key.grid_size)) {
239 for (const int x : IndexRange(key.grid_size)) {
240 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
241 const int node_vert = node_start + offset;
242 if (factors[node_vert] == 0.0f) {
243 continue;
244 }
245
246 SubdivCCGCoord coord{};
247 coord.grid_index = grids[i];
248 coord.x = x;
249 coord.y = y;
251 faces, corner_verts, vert_to_face_map, face_sets, subdiv_ccg, coord))
252 {
253 factors[node_vert] = 0.0f;
254 }
255 }
256 }
257 }
258}
259
261 const bool unique,
262 const Set<BMVert *, 0> &verts,
263 const MutableSpan<float> factors)
264{
265 BLI_assert(verts.size() == factors.size());
266
267 int i = 0;
268 for (const BMVert *vert : verts) {
269 if (unique == face_set::vert_has_unique_face_set(face_set_offset, *vert)) {
270 factors[i] = 0.0f;
271 }
272 i++;
273 }
274}
275
277
278/* -------------------------------------------------------------------- */
282
283static void face_sets_update(const Depsgraph &depsgraph,
284 Object &object,
285 const IndexMask &node_mask,
286 const FunctionRef<void(Span<int>, MutableSpan<int>)> calc_face_sets)
287{
288 SculptSession &ss = *object.sculpt;
289 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
290
292 *static_cast<Mesh *>(object.data));
293
294 struct TLS {
295 Vector<int> face_indices;
296 Vector<int> new_face_sets;
297 };
298
299 Array<bool> node_changed(pbvh.nodes_num(), false);
300
302 if (pbvh.type() == bke::pbvh::Type::Mesh) {
304 node_mask.foreach_index(GrainSize(1), [&](const int i) {
305 TLS &tls = all_tls.local();
306 const Span<int> faces = nodes[i].faces();
307
308 tls.new_face_sets.resize(faces.size());
309 MutableSpan<int> new_face_sets = tls.new_face_sets;
310 gather_data_mesh(face_sets.span.as_span(), faces, new_face_sets);
311 calc_face_sets(faces, new_face_sets);
312 if (array_utils::indexed_data_equal<int>(face_sets.span, faces, new_face_sets)) {
313 return;
314 }
315
317 scatter_data_mesh(new_face_sets.as_span(), faces, face_sets.span);
318 node_changed[i] = true;
319 });
320 }
321 else if (pbvh.type() == bke::pbvh::Type::Grids) {
323 node_mask.foreach_index(GrainSize(1), [&](const int i) {
324 TLS &tls = all_tls.local();
326 *ss.subdiv_ccg, nodes[i], tls.face_indices);
327
328 tls.new_face_sets.resize(faces.size());
329 MutableSpan<int> new_face_sets = tls.new_face_sets;
330 gather_data_mesh(face_sets.span.as_span(), faces, new_face_sets);
331 calc_face_sets(faces, new_face_sets);
332 if (array_utils::indexed_data_equal<int>(face_sets.span, faces, new_face_sets)) {
333 return;
334 }
335
337 scatter_data_mesh(new_face_sets.as_span(), faces, face_sets.span);
338 node_changed[i] = true;
339 });
340 }
341
342 IndexMaskMemory memory;
343 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
344 face_sets.finish();
345}
346
347enum class CreateMode {
350 All = 2,
352};
353
354static void clear_face_sets(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
355{
356 Mesh &mesh = *static_cast<Mesh *>(object.data);
357 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
358 if (!attributes.contains(".sculpt_face_set")) {
359 return;
360 }
361 SculptSession &ss = *object.sculpt;
362 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
363
364 Array<bool> node_changed(pbvh.nodes_num(), false);
365
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) {
370 node_mask.foreach_index(GrainSize(1), [&](const int i) {
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;
374 }))
375 {
377 node_changed[i] = true;
378 }
379 });
380 }
381 else if (pbvh.type() == bke::pbvh::Type::Grids) {
384 node_mask.foreach_index(GrainSize(1), [&](const int i) {
385 Vector<int> &face_indices = all_face_indices.local();
387 *ss.subdiv_ccg, nodes[i], face_indices);
388 if (std::any_of(faces.begin(), faces.end(), [&](const int face) {
389 return face_sets[face] != default_face_set;
390 }))
391 {
393 node_changed[i] = true;
394 }
395 });
396 }
397 IndexMaskMemory memory;
398 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
399 attributes.remove(".sculpt_face_set");
400}
401
403{
404 const Scene &scene = *CTX_data_scene(C);
405 Object &object = *CTX_data_active_object(C);
407
408 const CreateMode mode = CreateMode(RNA_enum_get(op->ptr, "mode"));
409
410 const View3D *v3d = CTX_wm_view3d(C);
411 const Base *base = CTX_data_active_base(C);
412 if (!BKE_base_is_visible(v3d, base)) {
413 return OPERATOR_CANCELLED;
414 }
415
416 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
417 if (pbvh.type() == bke::pbvh::Type::BMesh) {
418 /* Dyntopo not supported. */
419 return OPERATOR_CANCELLED;
420 }
421
422 Mesh &mesh = *static_cast<Mesh *>(object.data);
423 const bke::AttributeAccessor attributes = mesh.attributes();
424
426
427 undo::push_begin(scene, object, op);
428
429 const int next_face_set = find_next_available_id(object);
430
431 IndexMaskMemory memory;
432 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
433 switch (mode) {
434 case CreateMode::Masked: {
435 if (pbvh.type() == bke::pbvh::Type::Mesh) {
436 const OffsetIndices faces = mesh.faces();
437 const Span<int> corner_verts = mesh.corner_verts();
438 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
440 const VArraySpan<float> mask = *attributes.lookup<float>(".sculpt_mask",
442 if (!mask.is_empty()) {
444 object,
445 node_mask,
446 [&](const Span<int> indices, MutableSpan<int> face_sets) {
447 for (const int i : indices.index_range()) {
448 if (!hide_poly.is_empty() && hide_poly[indices[i]]) {
449 continue;
450 }
451 const Span<int> face_verts = corner_verts.slice(faces[indices[i]]);
452 if (!std::any_of(face_verts.begin(),
453 face_verts.end(),
454 [&](const int vert) { return mask[vert] > 0.5f; }))
455 {
456 continue;
457 }
458 face_sets[i] = next_face_set;
459 }
460 });
461 }
462 }
463 else if (pbvh.type() == bke::pbvh::Type::Grids) {
464 const OffsetIndices<int> faces = mesh.faces();
465 const SculptSession &ss = *object.sculpt;
466 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
467 const int grid_area = subdiv_ccg.grid_area;
468 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
470 const Span<float> masks = subdiv_ccg.masks;
471 if (!masks.is_empty()) {
473 object,
474 node_mask,
475 [&](const Span<int> indices, MutableSpan<int> face_sets) {
476 for (const int i : indices.index_range()) {
477 if (!hide_poly.is_empty() && hide_poly[indices[i]]) {
478 continue;
479 }
480
481 const Span<float> face_masks = masks.slice(
482 bke::ccg::face_range(faces, grid_area, indices[i]));
483 if (!std::any_of(face_masks.begin(),
484 face_masks.end(),
485 [&](const float mask) { return mask > 0.5f; }))
486 {
487 continue;
488 }
489 face_sets[i] = next_face_set;
490 }
491 });
492 }
493 }
494 break;
495 }
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)) {
502 /* If all vertices in the sculpt are visible, remove face sets and update the default
503 * color. This way the new face set will be white, and it is a quick way of disabling all
504 * face sets and the performance hit of rendering the overlay. */
505 clear_face_sets(depsgraph, object, node_mask);
506 break;
508 const VArraySpan<bool> hide_poly_span(hide_poly);
510 object,
511 node_mask,
512 [&](const Span<int> indices, MutableSpan<int> face_sets) {
513 for (const int i : indices.index_range()) {
514 if (!hide_poly_span[indices[i]]) {
515 face_sets[i] = next_face_set;
516 }
517 }
518 });
519 break;
520 }
521 break;
522 }
523 case CreateMode::All: {
525 object,
526 node_mask,
527 [&](const Span<int> /*indices*/, MutableSpan<int> face_sets) {
528 face_sets.fill(next_face_set);
529 });
530 break;
531 }
533 const VArraySpan<bool> select_poly = *attributes.lookup_or_default<bool>(
534 ".select_poly", bke::AttrDomain::Face, false);
535 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
537
539 depsgraph, object, node_mask, [&](const Span<int> indices, MutableSpan<int> face_sets) {
540 for (const int i : indices.index_range()) {
541 if (select_poly[indices[i]]) {
542 if (!hide_poly.is_empty() && hide_poly[i]) {
543 continue;
544 }
545 face_sets[i] = next_face_set;
546 }
547 }
548 });
549
550 break;
551 }
552 }
553
554 undo::push_end(object);
555
557
558 return OPERATOR_FINISHED;
559}
560
562{
563 ot->name = "Create Face Set";
564 ot->idname = "SCULPT_OT_face_sets_create";
565 ot->description = "Create a new Face Set";
566
567 ot->exec = create_op_exec;
568 ot->poll = SCULPT_mode_poll;
569
571
572 static EnumPropertyItem modes[] = {
574 "MASKED",
575 0,
576 "Face Set from Masked",
577 "Create a new Face Set from the masked faces"},
579 "VISIBLE",
580 0,
581 "Face Set from Visible",
582 "Create a new Face Set from the visible vertices"},
584 "ALL",
585 0,
586 "Face Set Full Mesh",
587 "Create an unique Face Set with all faces in the sculpt"},
589 "SELECTION",
590 0,
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},
594 };
595 RNA_def_enum(ot->srna, "mode", modes, int(CreateMode::Masked), "Mode", "");
596}
597
608
609using FaceSetsFloodFillFn = FunctionRef<bool(int from_face, int edge, int to_face)>;
610
611static void init_flood_fill(Object &ob, const FaceSetsFloodFillFn &test_fn)
612{
613 SculptSession &ss = *ob.sculpt;
614 Mesh *mesh = static_cast<Mesh *>(ob.data);
615
616 BitVector<> visited_faces(mesh->faces_num, false);
617
619
620 const Span<int2> edges = mesh->edges();
621 const OffsetIndices faces = mesh->faces();
622 const Span<int> corner_edges = mesh->corner_edges();
623
624 if (ss.edge_to_face_map.is_empty()) {
626 faces, corner_edges, edges.size(), ss.edge_to_face_offsets, ss.edge_to_face_indices);
627 }
628
629 const bke::AttributeAccessor attributes = mesh->attributes();
630 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
631 const Set<int> hidden_face_sets = gather_hidden_face_sets(hide_poly, face_sets.span);
632
633 int next_face_set = 1;
634
635 for (const int i : faces.index_range()) {
636 if (!hide_poly.is_empty() && hide_poly[i]) {
637 continue;
638 }
639 if (visited_faces[i]) {
640 continue;
641 }
642 std::queue<int> queue;
643
644 while (hidden_face_sets.contains(next_face_set)) {
645 next_face_set += 1;
646 }
647 face_sets.span[i] = next_face_set;
648 visited_faces[i].set(true);
649 queue.push(i);
650
651 while (!queue.empty()) {
652 const int face_i = queue.front();
653 queue.pop();
654
655 for (const int edge_i : corner_edges.slice(faces[face_i])) {
656 for (const int neighbor_i : ss.edge_to_face_map[edge_i]) {
657 if (neighbor_i == face_i) {
658 continue;
659 }
660 if (visited_faces[neighbor_i]) {
661 continue;
662 }
663 if (!hide_poly.is_empty() && hide_poly[neighbor_i]) {
664 continue;
665 }
666 if (!test_fn(face_i, edge_i, neighbor_i)) {
667 continue;
668 }
669
670 face_sets.span[neighbor_i] = next_face_set;
671 visited_faces[neighbor_i].set(true);
672 queue.push(neighbor_i);
673 }
674 }
675 }
676
677 next_face_set += 1;
678 }
679
680 face_sets.finish();
681}
682
683Set<int> gather_hidden_face_sets(const Span<bool> hide_poly, const Span<int> face_sets)
684{
685 if (hide_poly.is_empty()) {
686 return {};
687 }
688
689 Set<int> hidden_face_sets;
690 for (const int i : hide_poly.index_range()) {
691 if (hide_poly[i]) {
692 hidden_face_sets.add(face_sets[i]);
693 }
694 }
695
696 return hidden_face_sets;
697}
698
700{
701 const Scene &scene = *CTX_data_scene(C);
704
705 const InitMode mode = InitMode(RNA_enum_get(op->ptr, "mode"));
706
707 const View3D *v3d = CTX_wm_view3d(C);
708 const Base *base = CTX_data_active_base(C);
709 if (!BKE_base_is_visible(v3d, base)) {
710 return OPERATOR_CANCELLED;
711 }
712
714
716 /* Dyntopo not supported. */
717 if (pbvh.type() == bke::pbvh::Type::BMesh) {
718 return OPERATOR_CANCELLED;
719 }
720
721 IndexMaskMemory memory;
722 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
723 if (node_mask.is_empty()) {
724 return OPERATOR_CANCELLED;
725 }
726
727 undo::push_begin(scene, ob, op);
729
730 const float threshold = RNA_float_get(op->ptr, "threshold");
731
732 Mesh *mesh = static_cast<Mesh *>(ob.data);
733 const bke::AttributeAccessor attributes = mesh->attributes();
734
735 switch (mode) {
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 /*edge*/, const int to_face) {
740 return hide_poly[from_face] == hide_poly[to_face];
741 });
742 break;
743 }
744 case InitMode::Materials: {
746 const VArraySpan<int> material_indices = *attributes.lookup_or_default<int>(
747 "material_index", bke::AttrDomain::Face, 0);
748 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly",
750 for (const int i : IndexRange(mesh->faces_num)) {
751 if (!hide_poly.is_empty() && hide_poly[i]) {
752 continue;
753 }
754
755 /* In some cases material face set index could be same as hidden face set index
756 * A more robust implementation is needed to avoid this */
757 face_sets.span[i] = material_indices[i] + 1;
758 }
759
760 face_sets.finish();
761 break;
762 }
763 case InitMode::Normals: {
764 const Span<float3> face_normals = mesh->face_normals();
765 init_flood_fill(ob, [&](const int from_face, const int /*edge*/, const int to_face) -> bool {
766 return std::abs(math::dot(face_normals[from_face], face_normals[to_face])) > threshold;
767 });
768 break;
769 }
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 /*from_face*/, const int edge, const int /*to_face*/) -> bool {
775 return !uv_seams[edge];
776 });
777 break;
778 }
779 case InitMode::Creases: {
780 const VArraySpan<float> creases = *attributes.lookup_or_default<float>(
781 "crease_edge", bke::AttrDomain::Edge, 0.0f);
783 [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
784 return creases[edge] < threshold;
785 });
786 break;
787 }
789 const VArraySpan<bool> sharp_edges = *mesh->attributes().lookup_or_default<bool>(
790 "sharp_edge", bke::AttrDomain::Edge, false);
792 [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
793 return !sharp_edges[edge];
794 });
795 break;
796 }
798 const VArraySpan<float> bevel_weights = *attributes.lookup_or_default<float>(
799 "bevel_weight_edge", bke::AttrDomain::Edge, 0.0f);
801 [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
802 return bevel_weights[edge] < threshold;
803 });
804 break;
805 }
807 Array<int> face_sets_copy = duplicate_face_sets(*mesh);
808 init_flood_fill(ob, [&](const int from_face, const int /*edge*/, const int to_face) -> bool {
809 return face_sets_copy[from_face] == face_sets_copy[to_face];
810 });
811 break;
812 }
813 }
814
815 undo::push_end(ob);
816
817 pbvh.tag_face_sets_changed(node_mask);
818
820
821 return OPERATOR_FINISHED;
822}
823
825{
826 ot->name = "Init Face Sets";
827 ot->idname = "SCULPT_OT_face_sets_init";
828 ot->description = "Initializes all Face Sets in the mesh";
829
830 ot->exec = init_op_exec;
831 ot->poll = SCULPT_mode_poll;
832
834
835 static EnumPropertyItem modes[] = {
837 "LOOSE_PARTS",
838 0,
839 "Face Sets from Loose Parts",
840 "Create a Face Set per loose part in the mesh"},
842 "MATERIALS",
843 0,
844 "Face Sets from Material Slots",
845 "Create a Face Set per Material Slot"},
847 "NORMALS",
848 0,
849 "Face Sets from Mesh Normals",
850 "Create Face Sets for Faces that have similar normal"},
852 "UV_SEAMS",
853 0,
854 "Face Sets from UV Seams",
855 "Create Face Sets using UV Seams as boundaries"},
857 "CREASES",
858 0,
859 "Face Sets from Edge Creases",
860 "Create Face Sets using Edge Creases as boundaries"},
862 "BEVEL_WEIGHT",
863 0,
864 "Face Sets from Bevel Weight",
865 "Create Face Sets using Bevel Weights as boundaries"},
867 "SHARP_EDGES",
868 0,
869 "Face Sets from Sharp Edges",
870 "Create Face Sets using Sharp Edges as boundaries"},
872 "FACE_SET_BOUNDARIES",
873 0,
874 "Face Sets from Face Set Boundaries",
875 "Create a Face Set per isolated Face Set"},
876 {0, nullptr, 0, nullptr, nullptr},
877 };
878 RNA_def_enum(ot->srna, "mode", modes, int(InitMode::LooseParts), "Mode", "");
880 ot->srna,
881 "threshold",
882 0.5f,
883 0.0f,
884 1.0f,
885 "Threshold",
886 "Minimum value to consider a certain attribute a boundary when creating the Face Sets",
887 0.0f,
888 1.0f);
889}
890
891enum class VisibilityMode {
895};
896
897static void face_hide_update(const Depsgraph &depsgraph,
898 Object &object,
899 const IndexMask &node_mask,
900 const FunctionRef<void(Span<int>, MutableSpan<bool>)> calc_hide)
901{
902 SculptSession &ss = *object.sculpt;
903 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
904 Mesh &mesh = *static_cast<Mesh *>(object.data);
905 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
907 ".hide_poly", bke::AttrDomain::Face);
908
909 struct TLS {
910 Vector<int> face_indices;
911 Vector<bool> new_hide;
912 };
913
914 Array<bool> node_changed(node_mask.min_array_size(), false);
915
917 if (pbvh.type() == bke::pbvh::Type::Mesh) {
919 node_mask.foreach_index(GrainSize(1), [&](const int i) {
920 TLS &tls = all_tls.local();
921 const Span<int> faces = nodes[i].faces();
922
923 tls.new_hide.resize(faces.size());
924 MutableSpan<bool> new_hide = tls.new_hide;
925 gather_data_mesh(hide_poly.span.as_span(), faces, new_hide);
926 calc_hide(faces, new_hide);
927 if (array_utils::indexed_data_equal<bool>(hide_poly.span, faces, new_hide)) {
928 return;
929 }
930
932 scatter_data_mesh(new_hide.as_span(), faces, hide_poly.span);
933 node_changed[i] = true;
934 });
935 }
936 else if (pbvh.type() == bke::pbvh::Type::Grids) {
938 node_mask.foreach_index(GrainSize(1), [&](const int i) {
939 TLS &tls = all_tls.local();
941 *ss.subdiv_ccg, nodes[i], tls.face_indices);
942
943 tls.new_hide.resize(faces.size());
944 MutableSpan<bool> new_hide = tls.new_hide;
945 gather_data_mesh(hide_poly.span.as_span(), faces, new_hide);
946 calc_hide(faces, new_hide);
947 if (array_utils::indexed_data_equal<bool>(hide_poly.span, faces, new_hide)) {
948 return;
949 }
950
952 scatter_data_mesh(new_hide.as_span(), faces, hide_poly.span);
953 node_changed[i] = true;
954 });
955 }
956
957 hide_poly.finish();
958
959 IndexMaskMemory memory;
960 const IndexMask changed_nodes = IndexMask::from_bools(node_changed, memory);
961 if (changed_nodes.is_empty()) {
962 return;
963 }
965 pbvh.tag_visibility_changed(node_mask);
966}
967
968static void show_all(Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
969{
970 switch (bke::object::pbvh_get(object)->type()) {
972 hide::mesh_show_all(depsgraph, object, node_mask);
973 break;
975 hide::grids_show_all(depsgraph, object, node_mask);
976 break;
979 break;
980 }
981}
982
984{
985 const Scene &scene = *CTX_data_scene(C);
986 Object &object = *CTX_data_active_object(C);
987 SculptSession &ss = *object.sculpt;
989
992
993 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
994
995 if (pbvh.type() == bke::pbvh::Type::BMesh) {
996 /* Not supported for dyntopo. There is no active face. */
997 return OPERATOR_CANCELLED;
998 }
999
1000 const VisibilityMode mode = VisibilityMode(RNA_enum_get(op->ptr, "mode"));
1001 const int active_face_set = active_face_set_get(object);
1002
1003 undo::push_begin(scene, object, op);
1004
1005 IndexMaskMemory memory;
1006 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1007
1008 const bke::AttributeAccessor attributes = mesh->attributes();
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",
1012
1013 switch (mode) {
1015 if (hide_poly.contains(true) || face_sets.is_empty()) {
1016 show_all(depsgraph, object, node_mask);
1017 }
1018 else {
1020 depsgraph, object, node_mask, [&](const Span<int> faces, MutableSpan<bool> hide) {
1021 for (const int i : hide.index_range()) {
1022 hide[i] = face_sets[faces[i]] != active_face_set;
1023 }
1024 });
1025 }
1026 break;
1027 }
1029 if (face_sets.is_empty()) {
1030 show_all(depsgraph, object, node_mask);
1031 }
1032 else {
1034 depsgraph, object, node_mask, [&](const Span<int> faces, MutableSpan<bool> hide) {
1035 for (const int i : hide.index_range()) {
1036 if (face_sets[faces[i]] == active_face_set) {
1037 hide[i] = false;
1038 }
1039 }
1040 });
1041 }
1042 break;
1044 if (face_sets.is_empty()) {
1046 depsgraph, object, node_mask, [&](const Span<int> /*faces*/, MutableSpan<bool> hide) {
1047 hide.fill(true);
1048 });
1049 }
1050 else {
1052 depsgraph, object, node_mask, [&](const Span<int> faces, MutableSpan<bool> hide) {
1053 for (const int i : hide.index_range()) {
1054 if (face_sets[faces[i]] == active_face_set) {
1055 hide[i] = true;
1056 }
1057 }
1058 });
1059 }
1060 break;
1061 }
1062
1063 /* For modes that use the cursor active vertex, update the rotation origin for viewport
1064 * navigation. */
1067 if (std::holds_alternative<std::monostate>(ss.active_vert())) {
1068 ups->last_stroke_valid = false;
1069 }
1070 else {
1071 float location[3];
1072 copy_v3_v3(location, ss.active_vert_position(depsgraph, object));
1073 mul_m4_v3(object.object_to_world().ptr(), location);
1074 copy_v3_v3(ups->average_stroke_accum, location);
1075 ups->average_stroke_counter = 1;
1076 ups->last_stroke_valid = true;
1077 }
1078 }
1079
1080 undo::push_end(object);
1081
1082 bke::pbvh::update_visibility(object, pbvh);
1083
1084 islands::invalidate(*object.sculpt);
1086
1087 return OPERATOR_FINISHED;
1088}
1089
1091{
1093
1094 const View3D *v3d = CTX_wm_view3d(C);
1095 const Base *base = CTX_data_active_base(C);
1096 if (!BKE_base_is_visible(v3d, base)) {
1097 return OPERATOR_CANCELLED;
1098 }
1099
1100 /* Update the active vertex and Face Set using the cursor position to avoid relying on the paint
1101 * cursor updates. */
1103 const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
1105 SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
1106
1107 return change_visibility_exec(C, op);
1108}
1109
1111{
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";
1115
1116 ot->exec = change_visibility_exec;
1117 ot->invoke = change_visibility_invoke;
1118 ot->poll = SCULPT_mode_poll;
1119
1121
1122 static EnumPropertyItem modes[] = {
1124 "TOGGLE",
1125 0,
1126 "Toggle Visibility",
1127 "Hide all Face Sets except for the active one"},
1129 "SHOW_ACTIVE",
1130 0,
1131 "Show Active Face Set",
1132 "Show Active Face Set"},
1134 "HIDE_ACTIVE",
1135 0,
1136 "Hide Active Face Sets",
1137 "Hide Active Face Sets"},
1138 {0, nullptr, 0, nullptr, nullptr},
1139 };
1140 RNA_def_enum(ot->srna, "mode", modes, int(VisibilityMode::Toggle), "Mode", "");
1141}
1142
1144{
1146
1147 const View3D *v3d = CTX_wm_view3d(C);
1148 const Base *base = CTX_data_active_base(C);
1149 if (!BKE_base_is_visible(v3d, base)) {
1150 return OPERATOR_CANCELLED;
1151 }
1152
1154
1155 /* Dyntopo not supported. */
1156 if (pbvh.type() == bke::pbvh::Type::BMesh) {
1157 return OPERATOR_CANCELLED;
1158 }
1159
1160 Mesh *mesh = static_cast<Mesh *>(ob.data);
1161 const bke::AttributeAccessor attributes = mesh->attributes();
1162
1163 if (!attributes.contains(".sculpt_face_set")) {
1164 return OPERATOR_CANCELLED;
1165 }
1166
1167 const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1168 const int random_index = clamp_i(mesh->faces_num * BLI_hash_int_01(mesh->face_sets_color_seed),
1169 0,
1170 max_ii(0, mesh->faces_num - 1));
1171 mesh->face_sets_color_default = face_sets[random_index];
1172
1173 mesh->face_sets_color_seed += 1;
1174
1175 IndexMaskMemory memory;
1176 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1177 pbvh.tag_face_sets_changed(node_mask);
1178
1180
1181 return OPERATOR_FINISHED;
1182}
1183
1185{
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";
1189
1190 ot->exec = randomize_colors_exec;
1191 ot->poll = SCULPT_mode_poll;
1192
1193 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1194}
1195
1203
1204static void edit_grow_shrink(const Depsgraph &depsgraph,
1205 const Scene &scene,
1206 Object &object,
1207 const EditMode mode,
1208 const int active_face_set_id,
1209 const bool modify_hidden,
1210 wmOperator *op)
1211{
1212 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1213 Mesh &mesh = *static_cast<Mesh *>(object.data);
1214 const OffsetIndices faces = mesh.faces();
1215 const Span<int> corner_verts = mesh.corner_verts();
1216 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1217 const bke::AttributeAccessor attributes = mesh.attributes();
1218
1219 BLI_assert(attributes.contains(".sculpt_face_set"));
1220
1221 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1222 Array<int> prev_face_sets = duplicate_face_sets(mesh);
1223
1224 undo::push_begin(scene, object, op);
1225
1226 IndexMaskMemory memory;
1227 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1229 depsgraph, object, node_mask, [&](const Span<int> indices, MutableSpan<int> face_sets) {
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]) {
1233 continue;
1234 }
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) {
1239 continue;
1240 }
1241 if (prev_face_sets[neighbor_face_index] == active_face_set_id) {
1242 face_sets[i] = active_face_set_id;
1243 }
1244 }
1245 }
1246 }
1247 else {
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) {
1252 continue;
1253 }
1254 if (prev_face_sets[neighbor_face_index] != active_face_set_id) {
1255 face_sets[i] = prev_face_sets[neighbor_face_index];
1256 }
1257 }
1258 }
1259 }
1260 }
1261 }
1262 });
1263
1264 undo::push_end(object);
1265}
1266
1267static bool check_single_face_set(const Object &object, const bool check_visible_only)
1268{
1269 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1270 const bke::AttributeAccessor attributes = mesh.attributes();
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",
1274
1275 if (face_sets.is_empty()) {
1276 return true;
1277 }
1278 int first_face_set = SCULPT_FACE_SET_NONE;
1279 if (check_visible_only) {
1280 for (const int i : face_sets.index_range()) {
1281 if (!hide_poly.is_empty() && hide_poly[i]) {
1282 continue;
1283 }
1284 first_face_set = face_sets[i];
1285 break;
1286 }
1287 }
1288 else {
1289 first_face_set = face_sets[0];
1290 }
1291
1292 if (first_face_set == SCULPT_FACE_SET_NONE) {
1293 return true;
1294 }
1295
1296 for (const int i : face_sets.index_range()) {
1297 if (check_visible_only && !hide_poly.is_empty() && hide_poly[i]) {
1298 continue;
1299 }
1300 if (face_sets[i] != first_face_set) {
1301 return false;
1302 }
1303 }
1304 return true;
1305}
1306
1307static void delete_geometry(Object &ob, const int active_face_set_id, const bool modify_hidden)
1308{
1309 Mesh &mesh = *static_cast<Mesh *>(ob.data);
1310 const bke::AttributeAccessor attributes = mesh.attributes();
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",
1314
1315 const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&mesh);
1316 BMeshCreateParams create_params{};
1317 create_params.use_toolflags = true;
1318 BMesh *bm = BM_mesh_create(&allocsize, &create_params);
1319
1320 BMeshFromMeshParams convert_params{};
1321 convert_params.calc_vert_normal = true;
1322 convert_params.calc_face_normal = true;
1323 BM_mesh_bm_from_me(bm, &mesh, &convert_params);
1324
1328 BMIter iter;
1329 BMFace *f;
1330 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1331 const int face_index = BM_elem_index_get(f);
1332 if (!modify_hidden && !hide_poly.is_empty() && hide_poly[face_index]) {
1333 continue;
1334 }
1335 BM_elem_flag_set(f, BM_ELEM_TAG, face_sets[face_index] == active_face_set_id);
1336 }
1339
1340 BMeshToMeshParams bmesh_to_mesh_params{};
1341 bmesh_to_mesh_params.calc_object_remap = false;
1342 BM_mesh_bm_to_me(nullptr, bm, &mesh, &bmesh_to_mesh_params);
1343
1345}
1346
1347static void edit_fairing(const Depsgraph &depsgraph,
1348 const Sculpt &sd,
1349 Object &ob,
1350 const int active_face_set_id,
1351 const eMeshFairingDepth fair_order,
1352 const float strength)
1353{
1354 SculptSession &ss = *ob.sculpt;
1355 Mesh &mesh = *static_cast<Mesh *>(ob.data);
1358
1359 const PositionDeformData position_data(depsgraph, ob);
1360 const Span<float3> positions = position_data.eval;
1361 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1362 const BitSpan boundary_verts = ss.vertex_info.boundary;
1363 const bke::AttributeAccessor attributes = mesh.attributes();
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);
1366
1367 Array<bool> fair_verts(positions.size(), false);
1368 for (const int vert : positions.index_range()) {
1369 if (boundary::vert_is_boundary(vert_to_face_map, hide_poly, boundary_verts, vert)) {
1370 continue;
1371 }
1372 if (!vert_has_face_set(vert_to_face_map, face_sets, vert, active_face_set_id)) {
1373 continue;
1374 }
1375 if (!vert_has_unique_face_set(vert_to_face_map, face_sets, vert)) {
1376 continue;
1377 }
1378 fair_verts[vert] = true;
1379 }
1380
1381 Array<float3> new_positions = positions;
1382 BKE_mesh_prefair_and_fair_verts(&mesh, new_positions, fair_verts.data(), fair_order);
1383
1384 struct LocalData {
1385 Vector<float3> translations;
1386 };
1387
1388 IndexMaskMemory memory;
1389 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1391
1393 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1394 LocalData &tls = all_tls.local();
1395 const Span<int> verts = nodes[i].verts();
1396 tls.translations.resize(verts.size());
1397 const MutableSpan<float3> translations = tls.translations;
1398 for (const int i : verts.index_range()) {
1399 translations[i] = new_positions[verts[i]] - positions[verts[i]];
1400 }
1401 scale_translations(translations, strength);
1402 clip_and_lock_translations(sd, ss, positions, verts, translations);
1403 position_data.deform(translations, verts);
1404 });
1405}
1406
1407static bool edit_is_operation_valid(const Object &object,
1408 const EditMode mode,
1409 const bool modify_hidden)
1410{
1411 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1412 if (pbvh.type() == bke::pbvh::Type::BMesh) {
1413 /* Dyntopo is not supported. */
1414 return false;
1415 }
1416
1417 if (mode == EditMode::DeleteGeometry) {
1418 if (pbvh.type() == bke::pbvh::Type::Grids) {
1419 /* Modification of base mesh geometry requires special remapping of multi-resolution
1420 * displacement, which does not happen here.
1421 * Disable delete operation. It can be supported in the future by doing similar displacement
1422 * data remapping as what happens in the mesh edit mode. */
1423 return false;
1424 }
1425 if (check_single_face_set(object, !modify_hidden)) {
1426 /* Cancel the operator if the mesh only contains one Face Set to avoid deleting the
1427 * entire object. */
1428 return false;
1429 }
1430 }
1431
1433 if (pbvh.type() == bke::pbvh::Type::Grids) {
1434 /* TODO: Multi-resolution topology representation using grids and duplicates can't be used
1435 * directly by the fair algorithm. Multi-resolution topology needs to be exposed in a
1436 * different way or converted to a mesh for this operation. */
1437 return false;
1438 }
1439 }
1440
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);
1444 const bke::AttributeAccessor attributes = mesh.attributes();
1445 if (!attributes.contains(".sculpt_face_set")) {
1446 /* If a mesh does not have the face set attribute, growing or shrinking the face set will
1447 * have no effect, exit early in this case. */
1448 return false;
1449 }
1450 }
1451 }
1452
1453 return true;
1454}
1455
1457 bContext *C, Object &ob, const int active_face_set, const bool modify_hidden, wmOperator *op)
1458{
1459 const Scene &scene = *CTX_data_scene(C);
1460 Mesh *mesh = static_cast<Mesh *>(ob.data);
1461 undo::geometry_begin(scene, ob, op);
1462 delete_geometry(ob, active_face_set, modify_hidden);
1468}
1469
1471 bContext *C, Object &ob, const int active_face_set, const EditMode mode, wmOperator *op)
1472{
1473 const Scene &scene = *CTX_data_scene(C);
1474 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1475 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
1477 IndexMaskMemory memory;
1478 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1479
1480 const float strength = RNA_float_get(op->ptr, "strength");
1481
1482 undo::push_begin(scene, ob, op);
1484
1485 pbvh.tag_positions_changed(node_mask);
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
1501 undo::push_end(ob);
1502}
1503
1505{
1508 const EditMode mode = EditMode(RNA_enum_get(op->ptr, "mode"));
1509 const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden");
1510
1511 if (!edit_is_operation_valid(*ob, mode, modify_hidden)) {
1512 return false;
1513 }
1514
1516
1517 return true;
1518}
1519
1521{
1522 if (!edit_op_init(C, op)) {
1523 return OPERATOR_CANCELLED;
1524 }
1525
1526 const Scene &scene = *CTX_data_scene(C);
1527 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1529
1530 const int active_face_set = RNA_int_get(op->ptr, "active_face_set");
1531 const EditMode mode = EditMode(RNA_enum_get(op->ptr, "mode"));
1532 const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden");
1533
1534 switch (mode) {
1536 edit_modify_geometry(C, ob, active_face_set, modify_hidden, op);
1537 break;
1538 case EditMode::Grow:
1539 case EditMode::Shrink:
1540 edit_grow_shrink(depsgraph, scene, ob, mode, active_face_set, modify_hidden, op);
1541 break;
1544 edit_modify_coordinates(C, ob, active_face_set, mode, op);
1545 break;
1546 }
1547
1549
1550 return OPERATOR_FINISHED;
1551}
1552
1553static int edit_op_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1554{
1557
1558 const View3D *v3d = CTX_wm_view3d(C);
1559 const Base *base = CTX_data_active_base(C);
1560 if (!BKE_base_is_visible(v3d, base)) {
1561 return OPERATOR_CANCELLED;
1562 }
1563
1565
1566 /* Update the current active Face Set and Vertex as the operator can be used directly from the
1567 * tool without brush cursor. */
1569 const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
1570 if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
1571 /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */
1572 return OPERATOR_CANCELLED;
1573 }
1574 RNA_int_set(op->ptr, "active_face_set", active_face_set_get(ob));
1575
1576 return edit_op_exec(C, op);
1577}
1578
1580{
1581 ot->name = "Edit Face Set";
1582 ot->idname = "SCULPT_OT_face_set_edit";
1583 ot->description = "Edits the current active Face Set";
1584
1585 ot->invoke = edit_op_invoke;
1586 ot->exec = edit_op_exec;
1587 ot->poll = SCULPT_mode_poll;
1588
1590
1591 PropertyRNA *prop = RNA_def_int(
1592 ot->srna, "active_face_set", 1, 0, INT_MAX, "Active Face Set", "", 0, 64);
1594
1595 static EnumPropertyItem modes[] = {
1597 "GROW",
1598 0,
1599 "Grow Face Set",
1600 "Grows the Face Sets boundary by one face based on mesh topology"},
1602 "SHRINK",
1603 0,
1604 "Shrink Face Set",
1605 "Shrinks the Face Sets boundary by one face based on mesh topology"},
1607 "DELETE_GEOMETRY",
1608 0,
1609 "Delete Geometry",
1610 "Deletes the faces that are assigned to the Face Set"},
1612 "FAIR_POSITIONS",
1613 0,
1614 "Fair Positions",
1615 "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
1616 "vertex positions"},
1618 "FAIR_TANGENCY",
1619 0,
1620 "Fair Tangency",
1621 "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
1622 "vertex tangents"},
1623 {0, nullptr, 0, nullptr, nullptr},
1624 };
1625 RNA_def_enum(ot->srna, "mode", modes, int(EditMode::Grow), "Mode", "");
1626 RNA_def_float(ot->srna, "strength", 1.0f, 0.0f, 1.0f, "Strength", "", 0.0f, 1.0f);
1627
1628 ot->prop = RNA_def_boolean(ot->srna,
1629 "modify_hidden",
1630 false,
1631 "Modify Hidden",
1632 "Apply the edit operation to hidden geometry");
1633}
1634
1636
1637/* -------------------------------------------------------------------- */
1641
1647
1648static void gesture_begin(bContext &C, wmOperator &op, gesture::GestureData &gesture_data)
1649{
1650 const Scene &scene = *CTX_data_scene(&C);
1651 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C);
1653 undo::push_begin(scene, *gesture_data.vc.obact, &op);
1654}
1655
1656static void gesture_apply_mesh(gesture::GestureData &gesture_data, const IndexMask &node_mask)
1657{
1658 FaceSetOperation *face_set_operation = (FaceSetOperation *)gesture_data.operation;
1659 const int new_face_set = face_set_operation->new_face_set_id;
1660 const Depsgraph &depsgraph = *gesture_data.vc.depsgraph;
1661 Object &object = *gesture_data.vc.obact;
1662 Mesh &mesh = *static_cast<Mesh *>(object.data);
1663 bke::AttributeAccessor attributes = mesh.attributes();
1664 SculptSession &ss = *gesture_data.ss;
1665 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1666
1667 const Span<float3> positions = bke::pbvh::vert_positions_eval(depsgraph, object);
1668 const OffsetIndices<int> faces = mesh.faces();
1669 const Span<int> corner_verts = mesh.corner_verts();
1670 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1672
1673 struct TLS {
1674 Vector<int> face_indices;
1675 };
1676
1677 Array<bool> node_changed(pbvh.nodes_num(), false);
1678
1680 if (pbvh.type() == bke::pbvh::Type::Mesh) {
1682 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1684 bool any_updated = false;
1685 for (const int face : nodes[i].faces()) {
1686 if (!hide_poly.is_empty() && hide_poly[face]) {
1687 continue;
1688 }
1689 const Span<int> face_verts = corner_verts.slice(faces[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)) {
1693 continue;
1694 }
1695 face_sets.span[face] = new_face_set;
1696 any_updated = true;
1697 }
1698 if (any_updated) {
1699 node_changed[i] = true;
1700 }
1701 });
1702 }
1703 else if (pbvh.type() == bke::pbvh::Type::Grids) {
1705 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1706 TLS &tls = all_tls.local();
1709 *ss.subdiv_ccg, nodes[i], tls.face_indices);
1710
1711 bool any_updated = false;
1712 for (const int face : node_faces) {
1713 if (!hide_poly.is_empty() && hide_poly[face]) {
1714 continue;
1715 }
1716 const Span<int> face_verts = corner_verts.slice(faces[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)) {
1720 continue;
1721 }
1722 face_sets.span[face] = new_face_set;
1723 any_updated = true;
1724 }
1725 if (any_updated) {
1726 node_changed[i] = true;
1727 }
1728 });
1729 }
1730
1731 IndexMaskMemory memory;
1732 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
1733 face_sets.finish();
1734}
1735
1736static void gesture_apply_bmesh(gesture::GestureData &gesture_data, const IndexMask &node_mask)
1737{
1738 FaceSetOperation *face_set_operation = (FaceSetOperation *)gesture_data.operation;
1739 const Depsgraph &depsgraph = *gesture_data.vc.depsgraph;
1740 const int new_face_set = face_set_operation->new_face_set_id;
1741 SculptSession &ss = *gesture_data.ss;
1742 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(*gesture_data.vc.obact);
1744 BMesh *bm = ss.bm;
1745 const int offset = CustomData_get_offset_named(&bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
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 *>(
1801 MEM_cnew<FaceSetOperation>(__func__));
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
1812static int gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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
1834static int gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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
1856static int gesture_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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
1878static int gesture_polyline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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:341
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2099
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:97
#define BLI_assert(a)
Definition BLI_assert.h:50
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition BLI_hash.h:96
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)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ CD_PROP_INT32
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
@ PROP_HIDDEN
Definition RNA_types.hh:239
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define BM_ELEM_CD_SET_INT(ele, offset, f)
@ BM_ELEM_HIDDEN
@ BM_ELEM_TAG
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)
@ BM_FACES_OF_MESH
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)
#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:494
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr const T * end() const
Definition BLI_span.hh:225
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr const T * begin() const
Definition BLI_span.hh:221
constexpr bool is_empty() const
Definition BLI_span.hh:261
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
static VArray ForSingle(T value, const int64_t size)
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
bool contains(const StringRef attribute_id) 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:549
Span< NodeT > nodes() const
int nodes_num() const
Definition pbvh.cc:504
void tag_face_sets_changed(const IndexMask &node_mask)
Definition pbvh.cc:579
void tag_visibility_changed(const IndexMask &node_mask)
Definition pbvh.cc:562
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7159
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
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
static ushort indices[]
static float verts[][3]
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:2846
void update_bounds(const Depsgraph &depsgraph, const Object &object, Tree &pbvh)
Definition pbvh.cc:1183
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2612
void update_visibility(const Object &object, Tree &pbvh)
Definition pbvh.cc:1377
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:2482
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:454
void ensure_boundary_info(Object &object)
Definition sculpt.cc:5784
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)
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)
Definition sculpt.cc:294
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:254
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)
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)
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 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)
Definition sculpt.cc:198
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)
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, 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:59
void invalidate(SculptSession &ss)
Definition sculpt.cc:5909
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, Type type)
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void flush_update_done(const bContext *C, Object &ob, UpdateType update_type)
Definition sculpt.cc:5069
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7230
void flush_update_step(bContext *C, UpdateType update_type)
Definition sculpt.cc:4960
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7042
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6136
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6096
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:153
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_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)
Definition sculpt.cc:4580
void SCULPT_vertex_random_access_ensure(Object &object)
Definition sculpt.cc:144
bool SCULPT_mode_poll_view3d(bContext *C)
Definition sculpt.cc:3566
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3560
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:735
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:458
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
ActiveVert active_vert() const
Definition paint.cc:2180
blender::Array< int > edge_to_face_offsets
Definition BKE_paint.hh:390
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2224
blender::GroupedSpan< int > edge_to_face_map
Definition BKE_paint.hh:392
blender::Array< int > edge_to_face_indices
Definition BKE_paint.hh:391
blender::BitVector boundary
Definition BKE_paint.hh:351
blender::Array< float > masks
struct UnifiedPaintSettings unified_paint_settings
Object * obact
Definition ED_view3d.hh:71
Depsgraph * depsgraph
Definition ED_view3d.hh:68
void(* end)(bContext &, GestureData &)
void(* begin)(bContext &, wmOperator &, GestureData &)
void(* apply_for_symmetry_pass)(bContext &, GestureData &)
int mval[2]
Definition WM_types.hh:728
struct PointerRNA * ptr
float max
@ 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:4126
wmOperatorType * ot
Definition wm_files.cc:4125
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)