Blender V5.0
editface.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10#include "BLI_math_matrix.h"
11#include "BLI_math_vector.h"
12#include "BLI_math_vector.hh"
13#include "BLI_task.hh"
14#include "BLI_vector_set.hh"
15
16#include "DNA_mesh_types.h"
17#include "DNA_meshdata_types.h"
18#include "DNA_object_types.h"
19
20#include "BKE_attribute.hh"
21#include "BKE_context.hh"
22#include "BKE_customdata.hh"
23#include "BKE_mesh.hh"
24#include "BKE_mesh_mapping.hh"
25#include "BKE_object.hh"
26
27#include "ED_mesh.hh"
28#include "ED_screen.hh"
29#include "ED_select_utils.hh"
30#include "ED_view3d.hh"
31
32#include "WM_api.hh"
33#include "WM_types.hh"
34
35#include "DEG_depsgraph.hh"
37
38/* own include */
39
41 Object *ob,
42 const bool flush_selection,
43 const bool flush_hidden)
44{
45 using namespace blender;
46 Mesh *mesh = BKE_mesh_from_object(ob);
47 const int *index_array = nullptr;
48
49 BLI_assert(flush_selection || flush_hidden);
50
51 if (mesh == nullptr) {
52 return;
53 }
54
55 /* NOTE: call #BKE_mesh_flush_hidden_from_verts_ex first when changing hidden flags. */
56
57 /* we could call this directly in all areas that change selection,
58 * since this could become slow for realtime updates (circle-select for eg) */
59 if (flush_selection) {
61 }
62
64 Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
65
66 if (ob_eval == nullptr) {
67 return;
68 }
69
70 bke::AttributeAccessor attributes_me = mesh->attributes();
71 Mesh *me_orig = (Mesh *)ob_eval->runtime->data_orig;
72 bke::MutableAttributeAccessor attributes_orig = me_orig->attributes_for_write();
73 Mesh *mesh_eval = (Mesh *)ob_eval->runtime->data_eval;
74 bke::MutableAttributeAccessor attributes_eval = mesh_eval->attributes_for_write();
75 bool updated = false;
76
77 if (me_orig != nullptr && mesh_eval != nullptr && me_orig->faces_num == mesh->faces_num) {
78 /* Update the evaluated copy of the mesh. */
79 if (flush_hidden) {
80 const VArray<bool> hide_poly_me = *attributes_me.lookup_or_default<bool>(
81 ".hide_poly", bke::AttrDomain::Face, false);
82 bke::SpanAttributeWriter<bool> hide_poly_orig =
83 attributes_orig.lookup_or_add_for_write_only_span<bool>(".hide_poly",
85 hide_poly_me.materialize(hide_poly_orig.span);
86 hide_poly_orig.finish();
87 }
88 if (flush_selection) {
89 const VArray<bool> select_poly_me = *attributes_me.lookup_or_default<bool>(
90 ".select_poly", bke::AttrDomain::Face, false);
91 bke::SpanAttributeWriter<bool> select_poly_orig =
92 attributes_orig.lookup_or_add_for_write_only_span<bool>(".select_poly",
94 select_poly_me.materialize(select_poly_orig.span);
95 select_poly_orig.finish();
96 }
97
98 /* Mesh faces => Final derived faces */
99 if ((index_array = (const int *)CustomData_get_layer(&mesh_eval->face_data, CD_ORIGINDEX))) {
100 if (flush_hidden) {
101 const VArray<bool> hide_poly_orig = *attributes_orig.lookup_or_default<bool>(
102 ".hide_poly", bke::AttrDomain::Face, false);
103 bke::SpanAttributeWriter<bool> hide_poly_eval =
104 attributes_eval.lookup_or_add_for_write_only_span<bool>(".hide_poly",
106 for (const int i : IndexRange(mesh_eval->faces_num)) {
107 const int orig_face_index = index_array[i];
108 if (orig_face_index != ORIGINDEX_NONE) {
109 hide_poly_eval.span[i] = hide_poly_orig[orig_face_index];
110 }
111 }
112 hide_poly_eval.finish();
113 }
114 if (flush_selection) {
115 const VArray<bool> select_poly_orig = *attributes_orig.lookup_or_default<bool>(
116 ".select_poly", bke::AttrDomain::Face, false);
117 bke::SpanAttributeWriter<bool> select_poly_eval =
118 attributes_eval.lookup_or_add_for_write_only_span<bool>(".select_poly",
120 for (const int i : IndexRange(mesh_eval->faces_num)) {
121 const int orig_face_index = index_array[i];
122 if (orig_face_index != ORIGINDEX_NONE) {
123 select_poly_eval.span[i] = select_poly_orig[orig_face_index];
124 }
125 }
126 select_poly_eval.finish();
127 }
128
129 updated = true;
130 }
131 }
132
133 if (updated) {
134 if (flush_hidden) {
136 }
137 else {
139 }
140
141 DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT);
142 }
143 else {
145 }
146
148}
149
150void paintface_hide(bContext *C, Object *ob, const bool unselected)
151{
152 using namespace blender;
153 Mesh *mesh = BKE_mesh_from_object(ob);
154 if (mesh == nullptr || mesh->faces_num == 0) {
155 return;
156 }
157
158 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
160 ".hide_poly", bke::AttrDomain::Face);
162 ".select_poly", bke::AttrDomain::Face);
163
164 for (int i = 0; i < mesh->faces_num; i++) {
165 if (!hide_poly.span[i]) {
166 if (!select_poly.span[i] == unselected) {
167 hide_poly.span[i] = true;
168 }
169 }
170
171 if (hide_poly.span[i]) {
172 select_poly.span[i] = false;
173 }
174 }
175
176 hide_poly.finish();
177 select_poly.finish();
178
180
181 paintface_flush_flags(C, ob, true, true);
182}
183
184void paintface_reveal(bContext *C, Object *ob, const bool select)
185{
186 using namespace blender;
187 Mesh *mesh = BKE_mesh_from_object(ob);
188 if (mesh == nullptr || mesh->faces_num == 0) {
189 return;
190 }
191
192 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
193
194 if (select) {
195 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
196 ".hide_poly", bke::AttrDomain::Face, false);
198 ".select_poly", bke::AttrDomain::Face);
199 for (const int i : hide_poly.index_range()) {
200 if (hide_poly[i]) {
201 select_poly.span[i] = true;
202 }
203 }
204 select_poly.finish();
205 }
206
207 attributes.remove(".hide_poly");
208
210
211 paintface_flush_flags(C, ob, true, true);
212}
213
221 Mesh &mesh,
222 const bool skip_seams = true)
223{
224 using namespace blender;
225 const OffsetIndices faces = mesh.faces();
226 const Span<int> corner_edges = mesh.corner_edges();
227
228 const bke::AttributeAccessor attributes = mesh.attributes();
229 const VArray<bool> uv_seams = *attributes.lookup_or_default<bool>(
230 "uv_seam", bke::AttrDomain::Edge, false);
231 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
232 ".hide_poly", bke::AttrDomain::Face, false);
233
234 /* Faces are connected if they share edges. By connecting all edges of a loop (as long as they
235 * are not a seam) we can find connected faces. */
236 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
237 for (const int face_index : range) {
238 if (hide_poly[face_index]) {
239 continue;
240 }
241 const Span<int> face_edges = corner_edges.slice(faces[face_index]);
242
243 for (const int poly_loop_index : face_edges.index_range()) {
244 const int outer_edge = face_edges[poly_loop_index];
245 if (skip_seams && uv_seams[outer_edge]) {
246 continue;
247 }
248
249 for (const int inner_edge :
250 face_edges.slice(poly_loop_index, face_edges.size() - poly_loop_index))
251 {
252 if (outer_edge == inner_edge) {
253 continue;
254 }
255 if (skip_seams && uv_seams[inner_edge]) {
256 continue;
257 }
258 islands.join(inner_edge, outer_edge);
259 }
260 }
261 }
262 });
263}
264
265/* Select faces connected to the given face_indices. Seams are treated as separation. */
267 const blender::Span<int> face_indices,
268 const bool select)
269{
270 using namespace blender;
271
272 AtomicDisjointSet islands(mesh.edges_num);
273 build_poly_connections(islands, mesh);
274
275 const OffsetIndices faces = mesh.faces();
276 const Span<int> corner_edges = mesh.corner_edges();
277
278 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
279 const VArray<bool> uv_seams = *attributes.lookup_or_default<bool>(
280 "uv_seam", bke::AttrDomain::Edge, false);
282 ".select_poly", bke::AttrDomain::Face);
283
284 Set<int> selected_roots;
285 for (const int i : face_indices) {
286 for (const int edge : corner_edges.slice(faces[i])) {
287 if (uv_seams[edge]) {
288 continue;
289 }
290 const int root = islands.find_root(edge);
291 selected_roots.add(root);
292 }
293 }
294
295 threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) {
296 for (const int face_index : range) {
297 for (const int edge : corner_edges.slice(faces[face_index])) {
298 const int root = islands.find_root(edge);
299 if (selected_roots.contains(root)) {
300 select_poly.span[face_index] = select;
301 break;
302 }
303 }
304 }
305 });
306
307 select_poly.finish();
308}
309
310void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const bool select)
311{
312 using namespace blender;
313 Mesh *mesh = BKE_mesh_from_object(ob);
314 if (mesh == nullptr || mesh->faces_num == 0) {
315 return;
316 }
317
318 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
320 ".select_poly", bke::AttrDomain::Face);
321
323 if (mval) {
324 uint index = uint(-1);
325 if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
326 select_poly.finish();
327 return;
328 }
329 /* Since paintface_select_linked_faces might not select the face under the cursor, select it
330 * here. */
331 select_poly.span[index] = true;
332 indices.append(index);
333 }
334
335 else {
336 for (const int i : select_poly.span.index_range()) {
337 if (!select_poly.span[i]) {
338 continue;
339 }
340 indices.append(i);
341 }
342 }
343
344 select_poly.finish();
345
347 paintface_flush_flags(C, ob, true, false);
348}
349
351 const blender::Span<int> corner_edges,
352 const int current_edge_index)
353{
354 const int index_in_poly = corner_edges.slice(face).first_index(current_edge_index);
355 /* Assumes that edge index of opposing face edge is always off by 2 on quads. */
356 if (index_in_poly >= 2) {
357 return corner_edges[face[index_in_poly - 2]];
358 }
359 /* Cannot be out of bounds because of the preceding if statement: if i < 2 then i+2 < 4. */
360 return corner_edges[face[index_in_poly + 2]];
361}
362
367static bool follow_face_loop(const int face_start_index,
368 const int edge_start_index,
370 const blender::VArray<bool> &hide_poly,
371 const blender::Span<int> corner_edges,
372 const blender::GroupedSpan<int> edge_to_face_map,
373 blender::VectorSet<int> &r_loop_faces)
374{
375 using namespace blender;
376 int current_face_index = face_start_index;
377 int current_edge_index = edge_start_index;
378
379 while (current_edge_index > 0) {
380 int next_face_index = -1;
381
382 for (const int face_index : edge_to_face_map[current_edge_index]) {
383 if (face_index != current_face_index) {
384 next_face_index = face_index;
385 break;
386 }
387 }
388
389 /* Edge might only have 1 face connected. */
390 if (next_face_index == -1) {
391 return false;
392 }
393
394 /* Only works on quads. */
395 if (faces[next_face_index].size() != 4) {
396 return false;
397 }
398
399 /* Happens if we looped around the mesh. */
400 if (r_loop_faces.contains(next_face_index)) {
401 return true;
402 }
403
404 /* Hidden faces stop selection. */
405 if (hide_poly[next_face_index]) {
406 return false;
407 }
408
409 r_loop_faces.add(next_face_index);
410
411 const IndexRange next_face = faces[next_face_index];
412 current_edge_index = get_opposing_edge_index(next_face, corner_edges, current_edge_index);
413 current_face_index = next_face_index;
414 }
415 return false;
416}
417
418void paintface_select_loop(bContext *C, Object *ob, const int mval[2], const bool select)
419{
420 using namespace blender;
421
425
426 Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
427 if (!ob_eval) {
428 return;
429 }
430
431 uint closest_edge_index = uint(-1);
432 if (!ED_mesh_pick_edge(C, ob, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, &closest_edge_index)) {
433 return;
434 }
435
436 if (closest_edge_index == -1) {
437 return;
438 }
439
440 ARegion *region = CTX_wm_region(C);
441 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
442 ED_view3d_init_mats_rv3d(ob_eval, rv3d);
443
444 Mesh *mesh = BKE_mesh_from_object(ob);
445 const Span<int> corner_edges = mesh->corner_edges();
446 const OffsetIndices faces = mesh->faces();
447
448 Array<int> edge_to_face_offsets;
449 Array<int> edge_to_face_indices;
451 faces, corner_edges, mesh->edges_num, edge_to_face_offsets, edge_to_face_indices);
452
453 VectorSet<int> faces_to_select;
454
455 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
456 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
457 ".hide_poly", bke::AttrDomain::Face, false);
458
459 const Span<int> faces_to_closest_edge = edge_to_face_map[closest_edge_index];
460
461 /* Picked edge may not be linked to a face (loose edge). */
462 if (faces_to_closest_edge.is_empty()) {
463 return;
464 }
465
466 const bool traced_full_loop = follow_face_loop(faces_to_closest_edge[0],
467 closest_edge_index,
468 faces,
469 hide_poly,
470 corner_edges,
471 edge_to_face_map,
472 faces_to_select);
473
474 if (!traced_full_loop && faces_to_closest_edge.size() > 1) {
475 /* Trace the other way. */
476 follow_face_loop(faces_to_closest_edge[1],
477 closest_edge_index,
478 faces,
479 hide_poly,
480 corner_edges,
481 edge_to_face_map,
482 faces_to_select);
483 }
484
486 ".select_poly", bke::AttrDomain::Face);
487
488 /* Toggling behavior. When one of the faces of the picked edge is already selected,
489 * it deselects the loop instead. */
490 bool any_adjacent_poly_selected = false;
491 for (const int i : faces_to_closest_edge) {
492 any_adjacent_poly_selected |= select_poly.span[i];
493 }
494 const bool select_toggle = select && !any_adjacent_poly_selected;
495 select_poly.span.fill_indices(faces_to_select.as_span(), select_toggle);
496
497 select_poly.finish();
498 paintface_flush_flags(C, ob, true, false);
499}
500
503 blender::Span<bool> select_vert,
504 const bool face_step)
505{
506 for (const int edge_index : face_edges) {
507 const blender::int2 &edge = edges[edge_index];
508 /* If a face is selected, all of its verts are selected too, meaning that neighboring faces
509 * will have some vertices selected. */
510 if (face_step) {
511 if (select_vert[edge[0]] || select_vert[edge[1]]) {
512 return true;
513 }
514 }
515 else {
516 if (select_vert[edge[0]] && select_vert[edge[1]]) {
517 return true;
518 }
519 }
520 }
521 return false;
522}
523
524void paintface_select_more(Mesh *mesh, const bool face_step)
525{
526 using namespace blender;
527
528 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
530 ".select_poly", bke::AttrDomain::Face);
532 ".select_vert", bke::AttrDomain::Point);
533 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
534 ".hide_poly", bke::AttrDomain::Face, false);
535
536 const OffsetIndices faces = mesh->faces();
537 const Span<int> corner_edges = mesh->corner_edges();
538 const Span<int2> edges = mesh->edges();
539
540 threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) {
541 for (const int i : range) {
542 if (select_poly.span[i] || hide_poly[i]) {
543 continue;
544 }
545 const IndexRange face = faces[i];
546 if (poly_has_selected_neighbor(corner_edges.slice(face), edges, select_vert.span, face_step))
547 {
548 select_poly.span[i] = true;
549 }
550 }
551 });
552
553 select_poly.finish();
554 select_vert.finish();
555}
556
559 blender::BitSpan verts_of_unselected_faces,
560 const bool face_step)
561{
562 for (const int edge_index : face_edges) {
563 const blender::int2 &edge = edges[edge_index];
564 if (face_step) {
565 if (verts_of_unselected_faces[edge[0]] || verts_of_unselected_faces[edge[1]]) {
566 return true;
567 }
568 }
569 else {
570 if (verts_of_unselected_faces[edge[0]] && verts_of_unselected_faces[edge[1]]) {
571 return true;
572 }
573 }
574 }
575 return false;
576}
577
578void paintface_select_less(Mesh *mesh, const bool face_step)
579{
580 using namespace blender;
581
582 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
584 ".select_poly", bke::AttrDomain::Face);
585 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
586 ".hide_poly", bke::AttrDomain::Face, false);
587
588 const OffsetIndices faces = mesh->faces();
589 const Span<int> corner_verts = mesh->corner_verts();
590 const Span<int> corner_edges = mesh->corner_edges();
591 const Span<int2> edges = mesh->edges();
592
593 BitVector<> verts_of_unselected_faces(mesh->verts_num);
594
595 /* Find all vertices of unselected faces to help find neighboring faces after. */
596 for (const int i : faces.index_range()) {
597 if (select_poly.span[i]) {
598 continue;
599 }
600 const IndexRange face = faces[i];
601 for (const int vert : corner_verts.slice(face)) {
602 verts_of_unselected_faces[vert].set(true);
603 }
604 }
605
606 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
607 for (const int i : range) {
608 if (!select_poly.span[i] || hide_poly[i]) {
609 continue;
610 }
611 const IndexRange face = faces[i];
612 if (poly_has_unselected_neighbor(
613 corner_edges.slice(face), edges, verts_of_unselected_faces, face_step))
614 {
615 select_poly.span[i] = false;
616 }
617 }
618 });
619
620 select_poly.finish();
621}
622
623bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)
624{
625 using namespace blender;
626 Mesh *mesh = BKE_mesh_from_object(ob);
627 if (mesh == nullptr) {
628 return false;
629 }
630
631 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
632 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
633 ".hide_poly", bke::AttrDomain::Face, false);
635 ".select_poly", bke::AttrDomain::Face);
636
637 if (action == SEL_TOGGLE) {
638 action = SEL_SELECT;
639
640 for (int i = 0; i < mesh->faces_num; i++) {
641 if (!hide_poly[i] && select_poly.span[i]) {
642 action = SEL_DESELECT;
643 break;
644 }
645 }
646 }
647
648 bool changed = false;
649
650 for (int i = 0; i < mesh->faces_num; i++) {
651 if (hide_poly[i]) {
652 continue;
653 }
654 const bool old_selection = select_poly.span[i];
655 switch (action) {
656 case SEL_SELECT:
657 select_poly.span[i] = true;
658 break;
659 case SEL_DESELECT:
660 select_poly.span[i] = false;
661 break;
662 case SEL_INVERT:
663 select_poly.span[i] = !select_poly.span[i];
664 changed = true;
665 break;
666 }
667 if (old_selection != select_poly.span[i]) {
668 changed = true;
669 }
670 }
671
672 select_poly.finish();
673
674 if (changed) {
675 if (flush_flags) {
676 paintface_flush_flags(C, ob, true, false);
677 }
678 }
679 return changed;
680}
681
682bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
683{
684 using namespace blender;
685 bool ok = false;
686 float vec[3], bmat[3][3];
687
688 const Mesh *mesh = BKE_mesh_from_object(ob);
689 if (!mesh || !CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2)) {
690 return ok;
691 }
692
693 copy_m3_m4(bmat, ob->object_to_world().ptr());
694
695 const Span<float3> positions = mesh->vert_positions();
696 const OffsetIndices faces = mesh->faces();
697 const Span<int> corner_verts = mesh->corner_verts();
698 bke::AttributeAccessor attributes = mesh->attributes();
699 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
700 ".hide_poly", bke::AttrDomain::Face, false);
701 const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
702 ".select_poly", bke::AttrDomain::Face, false);
703
704 for (int i = 0; i < mesh->faces_num; i++) {
705 if (hide_poly[i] || !select_poly[i]) {
706 continue;
707 }
708
709 for (const int vert : corner_verts.slice(faces[i])) {
710 mul_v3_m3v3(vec, bmat, positions[vert]);
711 add_v3_v3v3(vec, vec, ob->object_to_world().location());
712 minmax_v3v3_v3(r_min, r_max, vec);
713 }
714
715 ok = true;
716 }
717
718 return ok;
719}
720
722 const int mval[2],
724 Object *ob)
725{
726 using namespace blender;
727 uint index;
728 bool changed = false;
729 bool found = false;
730
731 /* Get the face under the cursor */
732 Mesh *mesh = BKE_mesh_from_object(ob);
733
734 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
735 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
736 ".hide_poly", bke::AttrDomain::Face, false);
737 bke::AttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write<bool>(
738 ".select_poly", bke::AttrDomain::Face);
739
740 if (ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
741 if (index < mesh->faces_num) {
742 if (!hide_poly[index]) {
743 found = true;
744 }
745 }
746 }
747
748 if (params.sel_op == SEL_OP_SET) {
749 if ((found && params.select_passthrough) && select_poly.varray[index]) {
750 found = false;
751 }
752 else if (found || params.deselect_all) {
753 /* Deselect everything. */
754 changed |= paintface_deselect_all_visible(C, ob, SEL_DESELECT, false);
755 }
756 }
757
758 if (found) {
759 mesh->act_face = int(index);
760
761 switch (params.sel_op) {
762 case SEL_OP_SET:
763 case SEL_OP_ADD:
764 select_poly.varray.set(index, true);
765 break;
766 case SEL_OP_SUB:
767 select_poly.varray.set(index, false);
768 break;
769 case SEL_OP_XOR:
770 select_poly.varray.set(index, !select_poly.varray[index]);
771 break;
772 case SEL_OP_AND:
773 BLI_assert_unreachable(); /* Doesn't make sense for picking. */
774 break;
775 }
776
777 /* image window redraw */
778
779 paintface_flush_flags(C, ob, true, false);
780 ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */
781 changed = true;
782 }
783 select_poly.finish();
784 return changed || found;
785}
786
788{
789 using namespace blender;
790 Mesh *mesh = BKE_mesh_from_object(ob);
791 Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
792 if (mesh == nullptr) {
793 return;
794 }
795
796 /* we could call this directly in all areas that change selection,
797 * since this could become slow for realtime updates (circle-select for eg) */
799
800 if (mesh_eval == nullptr) {
801 return;
802 }
803
804 const bke::AttributeAccessor attributes_orig = mesh->attributes();
805 bke::MutableAttributeAccessor attributes_eval = mesh_eval->attributes_for_write();
806
807 const int *orig_indices = (const int *)CustomData_get_layer(&mesh_eval->vert_data, CD_ORIGINDEX);
808
809 const VArray<bool> hide_vert_orig = *attributes_orig.lookup_or_default<bool>(
810 ".hide_vert", bke::AttrDomain::Point, false);
811 bke::SpanAttributeWriter<bool> hide_vert_eval =
812 attributes_eval.lookup_or_add_for_write_only_span<bool>(".hide_vert",
814 if (orig_indices) {
815 for (const int i : hide_vert_eval.span.index_range()) {
816 if (orig_indices[i] != ORIGINDEX_NONE) {
817 hide_vert_eval.span[i] = hide_vert_orig[orig_indices[i]];
818 }
819 }
820 }
821 else {
822 hide_vert_orig.materialize(hide_vert_eval.span);
823 }
824 hide_vert_eval.finish();
825
826 const VArray<bool> select_vert_orig = *attributes_orig.lookup_or_default<bool>(
827 ".select_vert", bke::AttrDomain::Point, false);
828 bke::SpanAttributeWriter<bool> select_vert_eval =
829 attributes_eval.lookup_or_add_for_write_only_span<bool>(".select_vert",
831 if (orig_indices) {
832 for (const int i : select_vert_eval.span.index_range()) {
833 if (orig_indices[i] != ORIGINDEX_NONE) {
834 select_vert_eval.span[i] = select_vert_orig[orig_indices[i]];
835 }
836 }
837 }
838 else {
839 select_vert_orig.materialize(select_vert_eval.span);
840 }
841 select_vert_eval.finish();
842
844}
845
847 Object *ob,
848 const blender::Span<int> vertex_indices,
849 const bool select)
850{
851 using namespace blender;
852
853 Mesh *mesh = BKE_mesh_from_object(ob);
854 if (mesh == nullptr || mesh->faces_num == 0) {
855 return;
856 }
857
858 /* AtomicDisjointSet is used to store connection information in vertex indices. */
859 AtomicDisjointSet islands(mesh->verts_num);
860 const Span<int2> edges = mesh->edges();
861
862 /* By calling join() on the vertices of all edges, the AtomicDisjointSet contains information on
863 * which parts of the mesh are connected. */
864 threading::parallel_for(edges.index_range(), 1024, [&](const IndexRange range) {
865 for (const int2 &edge : edges.slice(range)) {
866 islands.join(edge[0], edge[1]);
867 }
868 });
869
870 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
872 ".select_vert", bke::AttrDomain::Point);
873
874 Set<int> selected_roots;
875
876 for (const int i : vertex_indices) {
877 const int root = islands.find_root(i);
878 selected_roots.add(root);
879 }
880
881 threading::parallel_for(select_vert.span.index_range(), 1024, [&](const IndexRange range) {
882 for (const int i : range) {
883 const int root = islands.find_root(i);
884 if (selected_roots.contains(root)) {
885 select_vert.span[i] = select;
886 }
887 }
888 });
889
890 select_vert.finish();
891
894}
895
897 Object *ob,
898 const int region_coordinates[2],
899 const bool select)
900{
901 uint index = uint(-1);
902 if (!ED_mesh_pick_vert(C, ob, region_coordinates, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index))
903 {
904 return;
905 }
906
907 paintvert_select_linked_vertices(C, ob, {int(index)}, select);
908}
909
911{
912 using namespace blender;
913 Mesh *mesh = BKE_mesh_from_object(ob);
914 if (mesh == nullptr || mesh->faces_num == 0) {
915 return;
916 }
917
918 blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
920 attributes.lookup_or_add_for_write_span<bool>(".select_vert", bke::AttrDomain::Point);
921
923 for (const int i : select_vert.span.index_range()) {
924 if (!select_vert.span[i]) {
925 continue;
926 }
927 indices.append(i);
928 }
929 select_vert.finish();
931}
932
933void paintvert_select_more(Mesh *mesh, const bool face_step)
934{
935 using namespace blender;
936
937 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
939 ".select_vert", bke::AttrDomain::Point);
940 const VArray<bool> hide_edge = *attributes.lookup_or_default<bool>(
941 ".hide_edge", bke::AttrDomain::Edge, false);
942 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
943 ".hide_poly", bke::AttrDomain::Face, false);
944
945 const OffsetIndices faces = mesh->faces();
946 const Span<int> corner_edges = mesh->corner_edges();
947 const Span<int> corner_verts = mesh->corner_verts();
948 const Span<int2> edges = mesh->edges();
949
950 Array<int> edge_to_face_offsets;
951 Array<int> edge_to_face_indices;
952 GroupedSpan<int> edge_to_face_map;
953 if (face_step) {
954 edge_to_face_map = bke::mesh::build_edge_to_face_map(
955 faces, corner_edges, mesh->edges_num, edge_to_face_offsets, edge_to_face_indices);
956 }
957
958 /* Need a copy of the selected verts that we can read from and is not modified. */
959 BitVector<> select_vert_original(mesh->verts_num, false);
960 for (int i = 0; i < mesh->verts_num; i++) {
961 select_vert_original[i].set(select_vert.span[i]);
962 }
963
964 /* If we iterated over faces we wouldn't extend the selection through edges that have no face
965 * attached to them. */
966 for (const int i : edges.index_range()) {
967 const int2 &edge = edges[i];
968 if ((!select_vert_original[edge[0]] && !select_vert_original[edge[1]]) || hide_edge[i]) {
969 continue;
970 }
971 select_vert.span[edge[0]] = true;
972 select_vert.span[edge[1]] = true;
973 if (!face_step) {
974 continue;
975 }
976 const Span<int> neighbor_polys = edge_to_face_map[i];
977 for (const int face_i : neighbor_polys) {
978 if (hide_poly[face_i]) {
979 continue;
980 }
981 const IndexRange face = faces[face_i];
982 for (const int vert : corner_verts.slice(face)) {
983 select_vert.span[vert] = true;
984 }
985 }
986 }
987
988 select_vert.finish();
989}
990
991void paintvert_select_less(Mesh *mesh, const bool face_step)
992{
993 using namespace blender;
994
995 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
997 ".select_vert", bke::AttrDomain::Point);
998 const VArray<bool> hide_edge = *attributes.lookup_or_default<bool>(
999 ".hide_edge", bke::AttrDomain::Edge, false);
1000 const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
1001 ".hide_poly", bke::AttrDomain::Face, false);
1002
1003 const OffsetIndices faces = mesh->faces();
1004 const Span<int> corner_edges = mesh->corner_edges();
1005 const Span<int> corner_verts = mesh->corner_verts();
1006 const Span<int2> edges = mesh->edges();
1007
1008 GroupedSpan<int> edge_to_face_map;
1009 Array<int> edge_to_face_offsets;
1010 Array<int> edge_to_face_indices;
1011 if (face_step) {
1012 edge_to_face_map = bke::mesh::build_edge_to_face_map(
1013 faces, corner_edges, edges.size(), edge_to_face_offsets, edge_to_face_indices);
1014 }
1015
1016 /* Need a copy of the selected verts that we can read from and is not modified. */
1017 BitVector<> select_vert_original(mesh->verts_num);
1018 for (int i = 0; i < mesh->verts_num; i++) {
1019 select_vert_original[i].set(select_vert.span[i]);
1020 }
1021
1022 for (const int i : edges.index_range()) {
1023 const int2 &edge = edges[i];
1024 if ((select_vert_original[edge[0]] && select_vert_original[edge[1]]) && !hide_edge[i]) {
1025 continue;
1026 }
1027 select_vert.span[edge[0]] = false;
1028 select_vert.span[edge[1]] = false;
1029
1030 if (!face_step) {
1031 continue;
1032 }
1033 for (const int face_i : edge_to_face_map[i]) {
1034 if (hide_poly[face_i]) {
1035 continue;
1036 }
1037 const IndexRange face = faces[face_i];
1038 for (const int vert : corner_verts.slice(face)) {
1039 select_vert.span[vert] = false;
1040 }
1041 }
1042 }
1043 select_vert.finish();
1044}
1045
1051
1052bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
1053{
1054 using namespace blender;
1055 Mesh *mesh = BKE_mesh_from_object(ob);
1056 if (mesh == nullptr) {
1057 return false;
1058 }
1059
1060 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
1061 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
1062 ".hide_vert", bke::AttrDomain::Point, false);
1063 bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
1064 ".select_vert", bke::AttrDomain::Point);
1065
1066 if (action == SEL_TOGGLE) {
1067 action = SEL_SELECT;
1068
1069 for (int i = 0; i < mesh->verts_num; i++) {
1070 if (!hide_vert[i] && select_vert.span[i]) {
1071 action = SEL_DESELECT;
1072 break;
1073 }
1074 }
1075 }
1076
1077 bool changed = false;
1078 for (int i = 0; i < mesh->verts_num; i++) {
1079 if (hide_vert[i]) {
1080 continue;
1081 }
1082 const bool old_selection = select_vert.span[i];
1083 switch (action) {
1084 case SEL_SELECT:
1085 select_vert.span[i] = true;
1086 break;
1087 case SEL_DESELECT:
1088 select_vert.span[i] = false;
1089 break;
1090 case SEL_INVERT:
1091 select_vert.span[i] = !select_vert.span[i];
1092 break;
1093 }
1094 if (old_selection != select_vert.span[i]) {
1095 changed = true;
1096 }
1097 }
1098
1099 select_vert.finish();
1100
1101 if (changed) {
1102 /* handle mselect */
1103 if (action == SEL_SELECT) {
1104 /* pass */
1105 }
1106 else if (ELEM(action, SEL_DESELECT, SEL_INVERT)) {
1108 }
1109 else {
1111 }
1112
1113 if (flush_flags) {
1115 }
1116 }
1117 return changed;
1118}
1119
1120void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
1121{
1122 using namespace blender;
1123 Mesh *mesh = BKE_mesh_from_object(ob);
1124 if (mesh == nullptr) {
1125 return;
1126 }
1127 const Span<MDeformVert> dverts = mesh->deform_verts();
1128 if (dverts.is_empty()) {
1129 return;
1130 }
1131
1132 if (!extend) {
1134 }
1135
1136 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
1137 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
1138 ".hide_vert", bke::AttrDomain::Point, false);
1139 bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
1140 ".select_vert", bke::AttrDomain::Point);
1141
1142 for (const int i : select_vert.span.index_range()) {
1143 if (!hide_vert[i]) {
1144 if (dverts[i].dw == nullptr) {
1145 /* if null weight then not grouped */
1146 select_vert.span[i] = true;
1147 }
1148 }
1149 }
1150
1151 select_vert.finish();
1152
1153 if (flush_flags) {
1155 }
1156}
1157
1158void paintvert_hide(bContext *C, Object *ob, const bool unselected)
1159{
1160 using namespace blender;
1161 Mesh *mesh = BKE_mesh_from_object(ob);
1162 if (mesh == nullptr || mesh->verts_num == 0) {
1163 return;
1164 }
1165
1166 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
1168 ".hide_vert", bke::AttrDomain::Point);
1169 bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
1170 ".select_vert", bke::AttrDomain::Point);
1171
1172 for (const int i : hide_vert.span.index_range()) {
1173 if (!hide_vert.span[i]) {
1174 if (!select_vert.span[i] == unselected) {
1175 hide_vert.span[i] = true;
1176 }
1177 }
1178
1179 if (hide_vert.span[i]) {
1180 select_vert.span[i] = false;
1181 }
1182 }
1183 hide_vert.finish();
1184 select_vert.finish();
1185
1187
1190}
1191
1192void paintvert_reveal(bContext *C, Object *ob, const bool select)
1193{
1194 using namespace blender;
1195 Mesh *mesh = BKE_mesh_from_object(ob);
1196 if (mesh == nullptr || mesh->verts_num == 0) {
1197 return;
1198 }
1199
1200 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
1201 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
1202 ".hide_vert", bke::AttrDomain::Point, false);
1203 bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
1204 ".select_vert", bke::AttrDomain::Point);
1205
1206 for (const int i : select_vert.span.index_range()) {
1207 if (hide_vert[i]) {
1208 select_vert.span[i] = select;
1209 }
1210 }
1211
1212 select_vert.finish();
1213
1214 /* Remove the hide attribute to reveal all vertices. */
1215 attributes.remove(".hide_vert");
1216
1218
1221}
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
#define ORIGINDEX_NONE
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void BKE_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode)
void BKE_mesh_mselect_clear(Mesh *mesh)
@ BKE_MESH_BATCH_DIRTY_SELECT_PAINT
Definition BKE_mesh.h:40
@ BKE_MESH_BATCH_DIRTY_ALL
Definition BKE_mesh.h:38
void BKE_mesh_mselect_validate(Mesh *mesh)
Mesh * BKE_mesh_from_object(Object *ob)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
unsigned int uint
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_SELECT
Definition DNA_ID.h:1101
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ CD_PROP_FLOAT2
Object is a sort of wrapper for general info.
#define ED_MESH_PICK_DEFAULT_VERT_DIST
Definition ED_mesh.hh:654
bool ED_mesh_pick_edge(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition meshtools.cc:701
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition meshtools.cc:567
#define ED_MESH_PICK_DEFAULT_FACE_DIST
Definition ED_mesh.hh:655
bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
Definition meshtools.cc:780
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
@ SEL_OP_AND
@ SEL_OP_XOR
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
void ED_view3d_init_mats_rv3d(const Object *ob, RegionView3D *rv3d)
void ED_view3d_select_id_validate(const ViewContext *vc)
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_SELECT
Definition WM_types.hh:508
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
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 IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
Span< Key > as_span() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t first_index(const T &search_value) const
Definition BLI_span.hh:377
IndexRange index_range() const
void materialize(MutableSpan< T > r_span) const
bool add(const Key &key)
bool contains(const Key &key) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
GAttributeWriter lookup_or_add_for_write(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
static void build_poly_connections(blender::AtomicDisjointSet &islands, Mesh &mesh, const bool skip_seams=true)
Definition editface.cc:220
static bool follow_face_loop(const int face_start_index, const int edge_start_index, const blender::OffsetIndices< int > faces, const blender::VArray< bool > &hide_poly, const blender::Span< int > corner_edges, const blender::GroupedSpan< int > edge_to_face_map, blender::VectorSet< int > &r_loop_faces)
Definition editface.cc:367
static bool poly_has_unselected_neighbor(blender::Span< int > face_edges, blender::Span< blender::int2 > edges, blender::BitSpan verts_of_unselected_faces, const bool face_step)
Definition editface.cc:557
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
Definition editface.cc:682
void paintvert_flush_flags(Object *ob)
Definition editface.cc:787
void paintface_flush_flags(bContext *C, Object *ob, const bool flush_selection, const bool flush_hidden)
Definition editface.cc:40
void paintface_reveal(bContext *C, Object *ob, const bool select)
Definition editface.cc:184
void paintvert_tag_select_update(bContext *C, Object *ob)
Definition editface.cc:1046
void paintface_hide(bContext *C, Object *ob, const bool unselected)
Definition editface.cc:150
void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
Definition editface.cc:1120
static int get_opposing_edge_index(const blender::IndexRange face, const blender::Span< int > corner_edges, const int current_edge_index)
Definition editface.cc:350
void paintface_select_less(Mesh *mesh, const bool face_step)
Definition editface.cc:578
void paintface_select_more(Mesh *mesh, const bool face_step)
Definition editface.cc:524
bool paintface_mouse_select(bContext *C, const int mval[2], const SelectPick_Params &params, Object *ob)
Definition editface.cc:721
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
Definition editface.cc:1052
void paintvert_select_linked(bContext *C, Object *ob)
Definition editface.cc:910
void paintvert_select_linked_pick(bContext *C, Object *ob, const int region_coordinates[2], const bool select)
Definition editface.cc:896
static void paintface_select_linked_faces(Mesh &mesh, const blender::Span< int > face_indices, const bool select)
Definition editface.cc:266
static bool poly_has_selected_neighbor(blender::Span< int > face_edges, blender::Span< blender::int2 > edges, blender::Span< bool > select_vert, const bool face_step)
Definition editface.cc:501
void paintvert_hide(bContext *C, Object *ob, const bool unselected)
Definition editface.cc:1158
void paintvert_reveal(bContext *C, Object *ob, const bool select)
Definition editface.cc:1192
void paintvert_select_less(Mesh *mesh, const bool face_step)
Definition editface.cc:991
bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)
Definition editface.cc:623
void paintface_select_loop(bContext *C, Object *ob, const int mval[2], const bool select)
Definition editface.cc:418
void paintvert_select_more(Mesh *mesh, const bool face_step)
Definition editface.cc:933
void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const bool select)
Definition editface.cc:310
static void paintvert_select_linked_vertices(bContext *C, Object *ob, const blender::Span< int > vertex_indices, const bool select)
Definition editface.cc:846
static ushort indices[]
#define select(A, B, C)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char faces[256]
static BMFace * face_step(BMEdge *edge, BMFace *f)
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)
void mesh_select_vert_flush(Mesh &mesh)
void mesh_hide_vert_flush(Mesh &mesh)
void mesh_hide_face_flush(Mesh &mesh)
void mesh_select_face_flush(Mesh &mesh)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< int32_t, 2 > int2
void * regiondata
Definition DNA_ID.h:414
int edges_num
CustomData corner_data
CustomData face_data
int act_face
CustomData vert_data
int faces_num
int verts_num
ObjectRuntimeHandle * runtime
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)