Blender  V2.93
editmesh_select.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2004 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_array.h"
27 #include "BLI_bitmap.h"
28 #include "BLI_heap.h"
29 #include "BLI_linklist.h"
30 #include "BLI_linklist_stack.h"
31 #include "BLI_listbase.h"
32 #include "BLI_math.h"
33 #include "BLI_math_bits.h"
34 #include "BLI_rand.h"
35 #include "BLI_utildefines_stack.h"
36 
37 #include "BKE_context.h"
38 #include "BKE_editmesh.h"
39 #include "BKE_layer.h"
40 #include "BKE_report.h"
41 
42 #include "WM_api.h"
43 #include "WM_types.h"
44 
45 #include "RNA_access.h"
46 #include "RNA_define.h"
47 #include "RNA_enum_types.h"
48 
49 #include "ED_mesh.h"
50 #include "ED_object.h"
51 #include "ED_screen.h"
52 #include "ED_select_utils.h"
53 #include "ED_transform.h"
54 #include "ED_view3d.h"
55 
56 #include "DNA_mesh_types.h"
57 #include "DNA_meshdata_types.h"
58 #include "DNA_object_types.h"
59 
60 #include "UI_resources.h"
61 
62 #include "bmesh_tools.h"
63 
64 #include "DEG_depsgraph.h"
65 #include "DEG_depsgraph_query.h"
66 
67 #include "DRW_select_buffer.h"
68 
69 #include "mesh_intern.h" /* own include */
70 
71 /* use bmesh operator flags for a few operators */
72 #define BMO_ELE_TAG 1
73 
74 /* -------------------------------------------------------------------- */
79  const Mesh *me,
80  const int axis,
81  const bool extend,
82  int *r_totmirr,
83  int *r_totfail)
84 {
85  BMesh *bm = em->bm;
86  BMIter iter;
87  int totmirr = 0;
88  int totfail = 0;
89  bool use_topology = me->editflag & ME_EDIT_MIRROR_TOPO;
90 
91  *r_totmirr = *r_totfail = 0;
92 
93  /* select -> tag */
95  BMVert *v;
96  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
98  }
99  }
100  else if (em->selectmode & SCE_SELECT_EDGE) {
101  BMEdge *e;
102  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
104  }
105  }
106  else {
107  BMFace *f;
108  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
110  }
111  }
112 
113  EDBM_verts_mirror_cache_begin(em, axis, true, true, false, use_topology);
114 
115  if (!extend) {
117  }
118 
120  BMVert *v;
121  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
123  BMVert *v_mirr = EDBM_verts_mirror_get(em, v);
124  if (v_mirr && !BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) {
125  BM_vert_select_set(bm, v_mirr, true);
126  totmirr++;
127  }
128  else {
129  totfail++;
130  }
131  }
132  }
133  }
134  else if (em->selectmode & SCE_SELECT_EDGE) {
135  BMEdge *e;
136  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
138  BMEdge *e_mirr = EDBM_verts_mirror_get_edge(em, e);
139  if (e_mirr && !BM_elem_flag_test(e_mirr, BM_ELEM_HIDDEN)) {
140  BM_edge_select_set(bm, e_mirr, true);
141  totmirr++;
142  }
143  else {
144  totfail++;
145  }
146  }
147  }
148  }
149  else {
150  BMFace *f;
151  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
153  BMFace *f_mirr = EDBM_verts_mirror_get_face(em, f);
154  if (f_mirr && !BM_elem_flag_test(f_mirr, BM_ELEM_HIDDEN)) {
155  BM_face_select_set(bm, f_mirr, true);
156  totmirr++;
157  }
158  else {
159  totfail++;
160  }
161  }
162  }
163  }
164 
166 
167  *r_totmirr = totmirr;
168  *r_totfail = totfail;
169 }
170 
173 /* -------------------------------------------------------------------- */
177 static BMElem *edbm_select_id_bm_elem_get(Base **bases, const uint sel_id, uint *r_base_index)
178 {
179  uint elem_id;
180  char elem_type = 0;
181  bool success = DRW_select_buffer_elem_get(sel_id, &elem_id, r_base_index, &elem_type);
182 
183  if (success) {
184  Object *obedit = bases[*r_base_index]->object;
185  BMEditMesh *em = BKE_editmesh_from_object(obedit);
186 
187  switch (elem_type) {
188  case SCE_SELECT_FACE:
189  return (BMElem *)BM_face_at_index_find_or_table(em->bm, elem_id);
190  case SCE_SELECT_EDGE:
191  return (BMElem *)BM_edge_at_index_find_or_table(em->bm, elem_id);
192  case SCE_SELECT_VERTEX:
193  return (BMElem *)BM_vert_at_index_find_or_table(em->bm, elem_id);
194  default:
195  BLI_assert(0);
196  return NULL;
197  }
198  }
199 
200  return NULL;
201 }
202 
205 /* -------------------------------------------------------------------- */
216 #define FIND_NEAR_SELECT_BIAS 5
217 #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
218 
220  float dist;
221  float dist_bias;
222  int index;
224 };
225 
227  float mval_fl[2];
229  bool use_cycle;
231 
234 };
235 
236 static void findnearestvert__doClosest(void *userData,
237  BMVert *eve,
238  const float screen_co[2],
239  int index)
240 {
241  struct NearestVertUserData *data = userData;
242  float dist_test, dist_test_bias;
243 
244  dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
245 
246  if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
247  dist_test_bias += FIND_NEAR_SELECT_BIAS;
248  }
249 
250  if (dist_test_bias < data->hit.dist_bias) {
251  data->hit.dist_bias = dist_test_bias;
252  data->hit.dist = dist_test;
253  data->hit.index = index;
254  data->hit.vert = eve;
255  }
256 
257  if (data->use_cycle) {
258  if ((data->hit_cycle.vert == NULL) && (index > data->cycle_index_prev) &&
259  (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) {
260  data->hit_cycle.dist_bias = dist_test_bias;
261  data->hit_cycle.dist = dist_test;
262  data->hit_cycle.index = index;
263  data->hit_cycle.vert = eve;
264  }
265  }
266 }
267 
280  float *dist_px_manhattan_p,
281  const bool use_select_bias,
282  bool use_cycle,
283  Base **bases,
284  uint bases_len,
285  uint *r_base_index)
286 {
287  uint base_index = 0;
288 
289  if (!XRAY_FLAG_ENABLED(vc->v3d)) {
290  uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region,
291  *dist_px_manhattan_p);
292  uint index;
293  BMVert *eve;
294 
295  /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
296  {
298 
300  vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
301 
302  if (index) {
303  eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index);
304  }
305  else {
306  eve = NULL;
307  }
308  }
309 
310  if (eve) {
311  if (dist_px_manhattan_test < *dist_px_manhattan_p) {
312  if (r_base_index) {
313  *r_base_index = base_index;
314  }
315  *dist_px_manhattan_p = dist_px_manhattan_test;
316  return eve;
317  }
318  }
319  return NULL;
320  }
321 
322  struct NearestVertUserData data = {{0}};
323  const struct NearestVertUserData_Hit *hit = NULL;
324  const eV3DProjTest clip_flag = RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d) ?
327  BMesh *prev_select_bm = NULL;
328 
329  static struct {
330  int index;
331  const BMVert *elem;
332  const BMesh *bm;
333  } prev_select = {0};
334 
335  data.mval_fl[0] = vc->mval[0];
336  data.mval_fl[1] = vc->mval[1];
337  data.use_select_bias = use_select_bias;
338  data.use_cycle = use_cycle;
339 
340  for (; base_index < bases_len; base_index++) {
341  Base *base_iter = bases[base_index];
343  if (use_cycle && prev_select.bm == vc->em->bm &&
344  prev_select.elem == BM_vert_at_index_find_or_table(vc->em->bm, prev_select.index)) {
345  data.cycle_index_prev = prev_select.index;
346  /* No need to compare in the rest of the loop. */
347  use_cycle = false;
348  }
349  else {
350  data.cycle_index_prev = 0;
351  }
352 
353  data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias =
354  *dist_px_manhattan_p;
355 
358 
359  hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit;
360 
361  if (hit->dist < *dist_px_manhattan_p) {
362  if (r_base_index) {
363  *r_base_index = base_index;
364  }
365  *dist_px_manhattan_p = hit->dist;
366  prev_select_bm = vc->em->bm;
367  }
368  }
369 
370  if (hit == NULL) {
371  return NULL;
372  }
373 
374  prev_select.index = hit->index;
375  prev_select.elem = hit->vert;
376  prev_select.bm = prev_select_bm;
377 
378  return hit->vert;
379 }
380 
381 BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
382 {
383  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
384  return EDBM_vert_find_nearest_ex(vc, dist_px_manhattan_p, false, false, &base, 1, NULL);
385 }
386 
387 /* find the distance to the edge we already have */
389  float mval_fl[2];
390  float dist;
392 };
393 
394 static void find_nearest_edge_center__doZBuf(void *userData,
395  BMEdge *eed,
396  const float screen_co_a[2],
397  const float screen_co_b[2],
398  int UNUSED(index))
399 {
400  struct NearestEdgeUserData_ZBuf *data = userData;
401 
402  if (eed == data->edge_test) {
403  float dist_test;
404  float screen_co_mid[2];
405 
406  mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
407  dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
408 
409  if (dist_test < data->dist) {
410  data->dist = dist_test;
411  }
412  }
413 }
414 
416  float dist;
417  float dist_bias;
418  int index;
420 
421  /* edges only, un-biased manhattan distance to which ever edge we pick
422  * (not used for choosing) */
424 };
425 
428  float mval_fl[2];
430  bool use_cycle;
432 
435 };
436 
437 /* note; uses v3d, so needs active 3d window */
439  void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
440 {
441  struct NearestEdgeUserData *data = userData;
442  float dist_test, dist_test_bias;
443 
444  float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
445  float screen_co[2];
446 
447  if (fac <= 0.0f) {
448  fac = 0.0f;
449  copy_v2_v2(screen_co, screen_co_a);
450  }
451  else if (fac >= 1.0f) {
452  fac = 1.0f;
453  copy_v2_v2(screen_co, screen_co_b);
454  }
455  else {
456  interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac);
457  }
458 
459  dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
460 
461  if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
462  dist_test_bias += FIND_NEAR_SELECT_BIAS;
463  }
464 
465  if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
466  float vec[3];
467 
468  interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac);
469  if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) {
470  return;
471  }
472  }
473 
474  if (dist_test_bias < data->hit.dist_bias) {
475  float screen_co_mid[2];
476 
477  data->hit.dist_bias = dist_test_bias;
478  data->hit.dist = dist_test;
479  data->hit.index = index;
480  data->hit.edge = eed;
481 
482  mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
483  data->hit.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
484  }
485 
486  if (data->use_cycle) {
487  if ((data->hit_cycle.edge == NULL) && (index > data->cycle_index_prev) &&
488  (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) {
489  float screen_co_mid[2];
490 
491  data->hit_cycle.dist_bias = dist_test_bias;
492  data->hit_cycle.dist = dist_test;
493  data->hit_cycle.index = index;
494  data->hit_cycle.edge = eed;
495 
496  mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
497  data->hit_cycle.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
498  }
499  }
500 }
501 
503  float *dist_px_manhattan_p,
504  float *r_dist_center_px_manhattan,
505  const bool use_select_bias,
506  bool use_cycle,
507  BMEdge **r_eed_zbuf,
508  Base **bases,
509  uint bases_len,
510  uint *r_base_index)
511 {
512  uint base_index = 0;
513 
514  if (!XRAY_FLAG_ENABLED(vc->v3d)) {
515  uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region,
516  *dist_px_manhattan_p);
517  uint index;
518  BMEdge *eed;
519 
520  /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
521  {
523 
525  vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
526 
527  if (index) {
528  eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index);
529  }
530  else {
531  eed = NULL;
532  }
533  }
534 
535  if (r_eed_zbuf) {
536  *r_eed_zbuf = eed;
537  }
538 
539  /* exception for faces (verts don't need this) */
540  if (r_dist_center_px_manhattan && eed) {
542 
543  data.mval_fl[0] = vc->mval[0];
544  data.mval_fl[1] = vc->mval[1];
545  data.dist = FLT_MAX;
546  data.edge_test = eed;
547 
549 
552 
553  *r_dist_center_px_manhattan = data.dist;
554  }
555  /* end exception */
556 
557  if (eed) {
558  if (dist_px_manhattan_test < *dist_px_manhattan_p) {
559  if (r_base_index) {
560  *r_base_index = base_index;
561  }
562  *dist_px_manhattan_p = dist_px_manhattan_test;
563  return eed;
564  }
565  }
566  return NULL;
567  }
568 
569  struct NearestEdgeUserData data = {{0}};
570  const struct NearestEdgeUserData_Hit *hit = NULL;
571  /* interpolate along the edge before doing a clipping plane test */
573  BMesh *prev_select_bm = NULL;
574 
575  static struct {
576  int index;
577  const BMEdge *elem;
578  const BMesh *bm;
579  } prev_select = {0};
580 
581  data.vc = *vc;
582  data.mval_fl[0] = vc->mval[0];
583  data.mval_fl[1] = vc->mval[1];
584  data.use_select_bias = use_select_bias;
585  data.use_cycle = use_cycle;
586 
587  for (; base_index < bases_len; base_index++) {
588  Base *base_iter = bases[base_index];
590  if (use_cycle && prev_select.bm == vc->em->bm &&
591  prev_select.elem == BM_edge_at_index_find_or_table(vc->em->bm, prev_select.index)) {
592  data.cycle_index_prev = prev_select.index;
593  /* No need to compare in the rest of the loop. */
594  use_cycle = false;
595  }
596  else {
597  data.cycle_index_prev = 0;
598  }
599 
600  data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias =
601  *dist_px_manhattan_p;
602 
605 
606  hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
607 
608  if (hit->dist < *dist_px_manhattan_p) {
609  if (r_base_index) {
610  *r_base_index = base_index;
611  }
612  *dist_px_manhattan_p = hit->dist;
613  prev_select_bm = vc->em->bm;
614  }
615  }
616 
617  if (hit == NULL) {
618  return NULL;
619  }
620 
621  if (r_dist_center_px_manhattan) {
622  *r_dist_center_px_manhattan = hit->dist_center_px_manhattan;
623  }
624 
625  prev_select.index = hit->index;
626  prev_select.elem = hit->edge;
627  prev_select.bm = prev_select_bm;
628 
629  return hit->edge;
630 }
631 
632 BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
633 {
634  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
636  vc, dist_px_manhattan_p, NULL, false, false, NULL, &base, 1, NULL);
637 }
638 
639 /* find the distance to the face we already have */
641  float mval_fl[2];
644 };
645 
646 static void find_nearest_face_center__doZBuf(void *userData,
647  BMFace *efa,
648  const float screen_co[2],
649  int UNUSED(index))
650 {
651  struct NearestFaceUserData_ZBuf *data = userData;
652 
653  if (efa == data->face_test) {
654  const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
655 
656  if (dist_test < data->dist_px_manhattan) {
657  data->dist_px_manhattan = dist_test;
658  }
659  }
660 }
661 
663  float dist;
664  float dist_bias;
665  int index;
667 };
668 
670  float mval_fl[2];
672  bool use_cycle;
674 
677 };
678 
679 static void findnearestface__doClosest(void *userData,
680  BMFace *efa,
681  const float screen_co[2],
682  int index)
683 {
684  struct NearestFaceUserData *data = userData;
685  float dist_test, dist_test_bias;
686 
687  dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
688 
689  if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
690  dist_test_bias += FIND_NEAR_SELECT_BIAS;
691  }
692 
693  if (dist_test_bias < data->hit.dist_bias) {
694  data->hit.dist_bias = dist_test_bias;
695  data->hit.dist = dist_test;
696  data->hit.index = index;
697  data->hit.face = efa;
698  }
699 
700  if (data->use_cycle) {
701  if ((data->hit_cycle.face == NULL) && (index > data->cycle_index_prev) &&
702  (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) {
703  data->hit_cycle.dist_bias = dist_test_bias;
704  data->hit_cycle.dist = dist_test;
705  data->hit_cycle.index = index;
706  data->hit_cycle.face = efa;
707  }
708  }
709 }
710 
719  float *dist_px_manhattan_p,
720  float *r_dist_center,
721  const bool use_zbuf_single_px,
722  const bool use_select_bias,
723  bool use_cycle,
724  BMFace **r_efa_zbuf,
725  Base **bases,
726  uint bases_len,
727  uint *r_base_index)
728 {
729  uint base_index = 0;
730 
731  if (!XRAY_FLAG_ENABLED(vc->v3d)) {
732  float dist_test;
733  uint index;
734  BMFace *efa;
735 
736  {
737  uint dist_px_manhattan_test = 0;
738  if (*dist_px_manhattan_p != 0.0f && (use_zbuf_single_px == false)) {
739  dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region,
740  *dist_px_manhattan_p);
741  }
742 
744 
745  if (dist_px_manhattan_test == 0) {
746  index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, vc->mval);
747  dist_test = 0.0f;
748  }
749  else {
751  vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
752  dist_test = dist_px_manhattan_test;
753  }
754 
755  if (index) {
756  efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index);
757  }
758  else {
759  efa = NULL;
760  }
761  }
762 
763  if (r_efa_zbuf) {
764  *r_efa_zbuf = efa;
765  }
766 
767  /* exception for faces (verts don't need this) */
768  if (r_dist_center && efa) {
770 
771  data.mval_fl[0] = vc->mval[0];
772  data.mval_fl[1] = vc->mval[1];
773  data.dist_px_manhattan = FLT_MAX;
774  data.face_test = efa;
775 
777 
780 
781  *r_dist_center = data.dist_px_manhattan;
782  }
783  /* end exception */
784 
785  if (efa) {
786  if (dist_test < *dist_px_manhattan_p) {
787  if (r_base_index) {
788  *r_base_index = base_index;
789  }
790  *dist_px_manhattan_p = dist_test;
791  return efa;
792  }
793  }
794  return NULL;
795  }
796 
797  struct NearestFaceUserData data = {{0}};
798  const struct NearestFaceUserData_Hit *hit = NULL;
799  const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
800  BMesh *prev_select_bm = NULL;
801 
802  static struct {
803  int index;
804  const BMFace *elem;
805  const BMesh *bm;
806  } prev_select = {0};
807 
808  data.mval_fl[0] = vc->mval[0];
809  data.mval_fl[1] = vc->mval[1];
810  data.use_select_bias = use_select_bias;
811  data.use_cycle = use_cycle;
812 
813  for (; base_index < bases_len; base_index++) {
814  Base *base_iter = bases[base_index];
816  if (use_cycle && prev_select.bm == vc->em->bm &&
817  prev_select.elem == BM_face_at_index_find_or_table(vc->em->bm, prev_select.index)) {
818  data.cycle_index_prev = prev_select.index;
819  /* No need to compare in the rest of the loop. */
820  use_cycle = false;
821  }
822  else {
823  data.cycle_index_prev = 0;
824  }
825 
826  data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias =
827  *dist_px_manhattan_p;
828 
831 
832  hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
833 
834  if (hit->dist < *dist_px_manhattan_p) {
835  if (r_base_index) {
836  *r_base_index = base_index;
837  }
838  *dist_px_manhattan_p = hit->dist;
839  prev_select_bm = vc->em->bm;
840  }
841  }
842 
843  if (hit == NULL) {
844  return NULL;
845  }
846 
847  if (r_dist_center) {
848  *r_dist_center = hit->dist;
849  }
850 
851  prev_select.index = hit->index;
852  prev_select.elem = hit->face;
853  prev_select.bm = prev_select_bm;
854 
855  return hit->face;
856 }
857 
858 BMFace *EDBM_face_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
859 {
860  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
862  vc, dist_px_manhattan_p, NULL, false, false, false, NULL, &base, 1, NULL);
863 }
864 
865 #undef FIND_NEAR_SELECT_BIAS
866 #undef FIND_NEAR_CYCLE_THRESHOLD_MIN
867 
868 /* best distance based on screen coords.
869  * use em->selectmode to define how to use
870  * selected vertices and edges get disadvantage
871  * return 1 if found one
872  */
874  Base **bases,
875  const uint bases_len,
876  int *r_base_index,
877  BMVert **r_eve,
878  BMEdge **r_eed,
879  BMFace **r_efa)
880 {
881  BMEditMesh *em = vc->em;
882  static short mval_prev[2] = {-1, -1};
883  /* only cycle while the mouse remains still */
884  const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
885  const float dist_init = ED_view3d_select_dist_px();
886  /* since edges select lines, we give dots advantage of ~20 pix */
887  const float dist_margin = (dist_init / 2);
888  float dist = dist_init;
889 
890  struct {
891  struct {
892  BMVert *ele;
893  int base_index;
894  } v;
895  struct {
896  BMEdge *ele;
897  int base_index;
898  } e, e_zbuf;
899  struct {
900  BMFace *ele;
901  int base_index;
902  } f, f_zbuf;
903  } hit = {{NULL}};
904 
905  /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
906 
907  if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_FACE)) {
908  float dist_center = 0.0f;
909  float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ?
910  &dist_center :
911  NULL;
912 
913  uint base_index = 0;
914  BMFace *efa_zbuf = NULL;
915  BMFace *efa_test = EDBM_face_find_nearest_ex(
916  vc, &dist, dist_center_p, true, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index);
917 
918  if (efa_test && dist_center_p) {
919  dist = min_ff(dist_margin, dist_center);
920  }
921  if (efa_test) {
922  hit.f.base_index = base_index;
923  hit.f.ele = efa_test;
924  }
925  if (efa_zbuf) {
926  hit.f_zbuf.base_index = base_index;
927  hit.f_zbuf.ele = efa_zbuf;
928  }
929  }
930 
931  if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
932  float dist_center = 0.0f;
933  float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
934 
935  uint base_index = 0;
936  BMEdge *eed_zbuf = NULL;
937  BMEdge *eed_test = EDBM_edge_find_nearest_ex(
938  vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf, bases, bases_len, &base_index);
939 
940  if (eed_test && dist_center_p) {
941  dist = min_ff(dist_margin, dist_center);
942  }
943  if (eed_test) {
944  hit.e.base_index = base_index;
945  hit.e.ele = eed_test;
946  }
947  if (eed_zbuf) {
948  hit.e_zbuf.base_index = base_index;
949  hit.e_zbuf.ele = eed_zbuf;
950  }
951  }
952 
953  if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_VERTEX)) {
954  uint base_index = 0;
955  BMVert *eve_test = EDBM_vert_find_nearest_ex(
956  vc, &dist, true, use_cycle, bases, bases_len, &base_index);
957 
958  if (eve_test) {
959  hit.v.base_index = base_index;
960  hit.v.ele = eve_test;
961  }
962  }
963 
964  /* return only one of 3 pointers, for frontbuffer redraws */
965  if (hit.v.ele) {
966  hit.f.ele = NULL;
967  hit.e.ele = NULL;
968  }
969  else if (hit.e.ele) {
970  hit.f.ele = NULL;
971  }
972 
973  /* there may be a face under the cursor, who's center if too far away
974  * use this if all else fails, it makes sense to select this */
975  if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) {
976  if (hit.e_zbuf.ele) {
977  hit.e.base_index = hit.e_zbuf.base_index;
978  hit.e.ele = hit.e_zbuf.ele;
979  }
980  else if (hit.f_zbuf.ele) {
981  hit.f.base_index = hit.f_zbuf.base_index;
982  hit.f.ele = hit.f_zbuf.ele;
983  }
984  }
985 
986  mval_prev[0] = vc->mval[0];
987  mval_prev[1] = vc->mval[1];
988 
989  /* Only one element type will be non-null. */
990  BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1);
991 
992  if (hit.v.ele) {
993  *r_base_index = hit.v.base_index;
994  }
995  if (hit.e.ele) {
996  *r_base_index = hit.e.base_index;
997  }
998  if (hit.f.ele) {
999  *r_base_index = hit.f.base_index;
1000  }
1001 
1002  *r_eve = hit.v.ele;
1003  *r_eed = hit.e.ele;
1004  *r_efa = hit.f.ele;
1005 
1006  return (hit.v.ele || hit.e.ele || hit.f.ele);
1007 }
1008 
1009 #undef FAKE_SELECT_MODE_BEGIN
1010 #undef FAKE_SELECT_MODE_END
1011 
1013  Base **bases,
1014  const uint bases_len,
1015  int *r_base_index,
1016  BMVert **r_eve,
1017  BMEdge **r_eed,
1018  BMFace **r_efa)
1019 {
1020  return unified_findnearest(vc, bases, bases_len, r_base_index, r_eve, r_eed, r_efa);
1021 }
1022 
1025 /* -------------------------------------------------------------------- */
1033  Base **bases,
1034  const uint bases_len,
1035  bool use_boundary_vertices,
1036  bool use_boundary_edges,
1037  int *r_base_index_vert,
1038  int *r_base_index_edge,
1039  int *r_base_index_face,
1040  struct BMVert **r_eve,
1041  struct BMEdge **r_eed,
1042  struct BMFace **r_efa)
1043 {
1044 
1045  const float mval_fl[2] = {UNPACK2(vc->mval)};
1046  float ray_origin[3], ray_direction[3];
1047 
1048  struct {
1049  uint base_index;
1050  BMElem *ele;
1051  } best = {0, NULL};
1052  /* Currently unused, keep since we may want to pick the best. */
1053  UNUSED_VARS(best);
1054 
1055  struct {
1056  uint base_index;
1057  BMElem *ele;
1058  } best_vert = {0, NULL};
1059 
1060  struct {
1061  uint base_index;
1062  BMElem *ele;
1063  } best_edge = {0, NULL};
1064 
1065  struct {
1066  uint base_index;
1067  BMElem *ele;
1068  } best_face = {0, NULL};
1069 
1071  vc->depsgraph, vc->region, vc->v3d, mval_fl, ray_origin, ray_direction, true)) {
1072  float dist_sq_best = FLT_MAX;
1073  float dist_sq_best_vert = FLT_MAX;
1074  float dist_sq_best_edge = FLT_MAX;
1075  float dist_sq_best_face = FLT_MAX;
1076 
1077  const bool use_vert = (r_eve != NULL);
1078  const bool use_edge = (r_eed != NULL);
1079  const bool use_face = (r_efa != NULL);
1080 
1081  for (uint base_index = 0; base_index < bases_len; base_index++) {
1082  Base *base_iter = bases[base_index];
1083  Object *obedit = base_iter->object;
1084 
1085  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1086  BMesh *bm = em->bm;
1087  float imat3[3][3];
1088 
1090  copy_m3_m4(imat3, obedit->obmat);
1091  invert_m3(imat3);
1092 
1093  const float(*coords)[3] = NULL;
1094  {
1095  Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data);
1096  if (me_eval->runtime.edit_data) {
1097  coords = me_eval->runtime.edit_data->vertexCos;
1098  }
1099  }
1100 
1101  if (coords != NULL) {
1103  }
1104 
1105  if ((use_boundary_vertices || use_boundary_edges) && (use_vert || use_edge)) {
1106  BMEdge *e;
1107  BMIter eiter;
1108  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
1109  if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && (BM_edge_is_boundary(e))) {
1110  if (use_vert && use_boundary_vertices) {
1111  for (uint j = 0; j < 2; j++) {
1112  BMVert *v = *((&e->v1) + j);
1113  float point[3];
1114  mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
1115  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1116  ray_origin, ray_direction, point);
1117  if (dist_sq_test < dist_sq_best_vert) {
1118  dist_sq_best_vert = dist_sq_test;
1119  best_vert.base_index = base_index;
1120  best_vert.ele = (BMElem *)v;
1121  }
1122  if (dist_sq_test < dist_sq_best) {
1123  dist_sq_best = dist_sq_test;
1124  best.base_index = base_index;
1125  best.ele = (BMElem *)v;
1126  }
1127  }
1128  }
1129 
1130  if (use_edge && use_boundary_edges) {
1131  float point[3];
1132 #if 0
1133  const float dist_sq_test = dist_squared_ray_to_seg_v3(
1134  ray_origin, ray_direction, e->v1->co, e->v2->co, point, &depth);
1135 #else
1136  if (coords) {
1137  mid_v3_v3v3(
1138  point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
1139  }
1140  else {
1141  mid_v3_v3v3(point, e->v1->co, e->v2->co);
1142  }
1143  mul_m4_v3(obedit->obmat, point);
1144  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1145  ray_origin, ray_direction, point);
1146  if (dist_sq_test < dist_sq_best_edge) {
1147  dist_sq_best_edge = dist_sq_test;
1148  best_edge.base_index = base_index;
1149  best_edge.ele = (BMElem *)e;
1150  }
1151  if (dist_sq_test < dist_sq_best) {
1152  dist_sq_best = dist_sq_test;
1153  best.base_index = base_index;
1154  best.ele = (BMElem *)e;
1155  }
1156 #endif
1157  }
1158  }
1159  }
1160  }
1161  /* Non boundary case. */
1162  if (use_vert && !use_boundary_vertices) {
1163  BMVert *v;
1164  BMIter viter;
1165  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
1166  if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
1167  float point[3];
1168  mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
1169  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1170  ray_origin, ray_direction, point);
1171  if (dist_sq_test < dist_sq_best_vert) {
1172  dist_sq_best_vert = dist_sq_test;
1173  best_vert.base_index = base_index;
1174  best_vert.ele = (BMElem *)v;
1175  }
1176  if (dist_sq_test < dist_sq_best) {
1177  dist_sq_best = dist_sq_test;
1178  best.base_index = base_index;
1179  best.ele = (BMElem *)v;
1180  }
1181  }
1182  }
1183  }
1184 
1185  if (use_edge && !use_boundary_edges) {
1186  BMEdge *e;
1187  BMIter eiter;
1188  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
1189  if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
1190  float point[3];
1191  if (coords) {
1192  mid_v3_v3v3(
1193  point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
1194  }
1195  else {
1196  mid_v3_v3v3(point, e->v1->co, e->v2->co);
1197  }
1198  mul_m4_v3(obedit->obmat, point);
1199  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1200  ray_origin, ray_direction, point);
1201  if (dist_sq_test < dist_sq_best_edge) {
1202  dist_sq_best_edge = dist_sq_test;
1203  best_edge.base_index = base_index;
1204  best_edge.ele = (BMElem *)e;
1205  }
1206  if (dist_sq_test < dist_sq_best) {
1207  dist_sq_best = dist_sq_test;
1208  best.base_index = base_index;
1209  best.ele = (BMElem *)e;
1210  }
1211  }
1212  }
1213  }
1214 
1215  if (use_face) {
1216  BMFace *f;
1217  BMIter fiter;
1218  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
1219  if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == false) {
1220  float point[3];
1221  if (coords) {
1222  BM_face_calc_center_median_vcos(bm, f, point, coords);
1223  }
1224  else {
1225  BM_face_calc_center_median(f, point);
1226  }
1227  mul_m4_v3(obedit->obmat, point);
1228  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1229  ray_origin, ray_direction, point);
1230  if (dist_sq_test < dist_sq_best_face) {
1231  dist_sq_best_face = dist_sq_test;
1232  best_face.base_index = base_index;
1233  best_face.ele = (BMElem *)f;
1234  }
1235  if (dist_sq_test < dist_sq_best) {
1236  dist_sq_best = dist_sq_test;
1237  best.base_index = base_index;
1238  best.ele = (BMElem *)f;
1239  }
1240  }
1241  }
1242  }
1243  }
1244  }
1245 
1246  *r_base_index_vert = best_vert.base_index;
1247  *r_base_index_edge = best_edge.base_index;
1248  *r_base_index_face = best_face.base_index;
1249 
1250  if (r_eve) {
1251  *r_eve = NULL;
1252  }
1253  if (r_eed) {
1254  *r_eed = NULL;
1255  }
1256  if (r_efa) {
1257  *r_efa = NULL;
1258  }
1259 
1260  if (best_vert.ele) {
1261  *r_eve = (BMVert *)best_vert.ele;
1262  }
1263  if (best_edge.ele) {
1264  *r_eed = (BMEdge *)best_edge.ele;
1265  }
1266  if (best_face.ele) {
1267  *r_efa = (BMFace *)best_face.ele;
1268  }
1269 
1270  return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL);
1271 }
1272 
1275 /* -------------------------------------------------------------------- */
1280 {
1281  Object *obedit = CTX_data_edit_object(C);
1282  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1283  BMesh *bm = em->bm;
1284  bool changed = false;
1285 
1286  /* group vars */
1287  int *groups_array;
1288  int(*group_index)[2];
1289  int group_tot;
1290  int i;
1291 
1292  if (bm->totfacesel < 2) {
1293  BKE_report(op->reports, RPT_ERROR, "No face regions selected");
1294  return OPERATOR_CANCELLED;
1295  }
1296 
1297  groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
1298  group_tot = BM_mesh_calc_face_groups(
1299  bm, groups_array, &group_index, NULL, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
1300 
1302 
1303  for (i = 0; i < group_tot; i++) {
1304  ListBase faces_regions;
1305  int tot;
1306 
1307  const int fg_sta = group_index[i][0];
1308  const int fg_len = group_index[i][1];
1309  int j;
1310  BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__);
1311 
1312  for (j = 0; j < fg_len; j++) {
1313  fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
1314  }
1315 
1316  tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions);
1317 
1318  MEM_freeN(fg);
1319 
1320  if (tot) {
1321  LinkData *link;
1322  while ((link = BLI_pophead(&faces_regions))) {
1323  BMFace *f, **faces = link->data;
1324  while ((f = *(faces++))) {
1325  BM_face_select_set(bm, f, true);
1326  }
1327  MEM_freeN(link->data);
1328  MEM_freeN(link);
1329 
1330  changed = true;
1331  }
1332  }
1333  }
1334 
1335  MEM_freeN(groups_array);
1336  MEM_freeN(group_index);
1337 
1338  if (changed) {
1341  }
1342  else {
1343  BKE_report(op->reports, RPT_WARNING, "No matching face regions found");
1344  }
1345 
1346  return OPERATOR_FINISHED;
1347 }
1348 
1350 {
1351  /* identifiers */
1352  ot->name = "Select Similar Regions";
1353  ot->idname = "MESH_OT_select_similar_region";
1354  ot->description = "Select similar face regions to the current selection";
1355 
1356  /* api callbacks */
1359 
1360  /* flags */
1362 }
1363 
1366 /* -------------------------------------------------------------------- */
1371 {
1372  const int type = RNA_enum_get(op->ptr, "type");
1373  const int action = RNA_enum_get(op->ptr, "action");
1374  const bool use_extend = RNA_boolean_get(op->ptr, "use_extend");
1375  const bool use_expand = RNA_boolean_get(op->ptr, "use_expand");
1376 
1377  if (EDBM_selectmode_toggle_multi(C, type, action, use_extend, use_expand)) {
1378  return OPERATOR_FINISHED;
1379  }
1380  return OPERATOR_CANCELLED;
1381 }
1382 
1383 static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1384 {
1385  /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */
1386  if (CTX_wm_space_image(C)) {
1388  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
1389  return OPERATOR_PASS_THROUGH;
1390  }
1391  /* Bypass when no action is needed. */
1392  if (!RNA_struct_property_is_set(op->ptr, "type")) {
1393  return OPERATOR_CANCELLED;
1394  }
1395  }
1396 
1397  /* detecting these options based on shift/ctrl here is weak, but it's done
1398  * to make this work when clicking buttons or menus */
1399  if (!RNA_struct_property_is_set(op->ptr, "use_extend")) {
1400  RNA_boolean_set(op->ptr, "use_extend", event->shift);
1401  }
1402  if (!RNA_struct_property_is_set(op->ptr, "use_expand")) {
1403  RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
1404  }
1405 
1406  return edbm_select_mode_exec(C, op);
1407 }
1408 
1410 {
1411  PropertyRNA *prop;
1412 
1413  static const EnumPropertyItem actions_items[] = {
1414  {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1415  {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1416  {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1417  {0, NULL, 0, NULL, NULL},
1418  };
1419 
1420  /* identifiers */
1421  ot->name = "Select Mode";
1422  ot->idname = "MESH_OT_select_mode";
1423  ot->description = "Change selection mode";
1424 
1425  /* api callbacks */
1429 
1430  /* flags */
1432 
1433  /* properties */
1434  /* Hide all, not to show redo panel. */
1435  prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", "");
1437  prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", "");
1439  ot->prop = prop = RNA_def_enum(ot->srna, "type", rna_enum_mesh_select_mode_items, 0, "Type", "");
1441 
1442  prop = RNA_def_enum(
1443  ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
1445 }
1446 
1449 /* -------------------------------------------------------------------- */
1454  int walkercode,
1455  void *start,
1456  int r_count_by_select[2])
1457 {
1458  BMesh *bm = em->bm;
1459  BMElem *ele;
1460  BMWalker walker;
1461 
1462  r_count_by_select[0] = r_count_by_select[1] = 0;
1463 
1464  BMW_init(&walker,
1465  bm,
1466  walkercode,
1467  BMW_MASK_NOP,
1468  BMW_MASK_NOP,
1469  BMW_MASK_NOP,
1471  BMW_NIL_LAY);
1472 
1473  for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1474  r_count_by_select[BM_elem_flag_test(ele, BM_ELEM_SELECT) ? 1 : 0] += 1;
1475 
1476  /* Early exit when mixed (could be optional if needed. */
1477  if (r_count_by_select[0] && r_count_by_select[1]) {
1478  r_count_by_select[0] = r_count_by_select[1] = -1;
1479  break;
1480  }
1481  }
1482 
1483  BMW_end(&walker);
1484 }
1485 
1486 static void walker_select(BMEditMesh *em, int walkercode, void *start, const bool select)
1487 {
1488  BMesh *bm = em->bm;
1489  BMElem *ele;
1490  BMWalker walker;
1491 
1492  BMW_init(&walker,
1493  bm,
1494  walkercode,
1495  BMW_MASK_NOP,
1496  BMW_MASK_NOP,
1497  BMW_MASK_NOP,
1499  BMW_NIL_LAY);
1500 
1501  for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1502  if (!select) {
1504  }
1505  BM_elem_select_set(bm, ele, select);
1506  }
1507  BMW_end(&walker);
1508 }
1509 
1511 {
1512  const bool is_ring = RNA_boolean_get(op->ptr, "ring");
1513  ViewLayer *view_layer = CTX_data_view_layer(C);
1514  uint objects_len = 0;
1516  view_layer, CTX_wm_view3d(C), &objects_len);
1517  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1518  Object *obedit = objects[ob_index];
1519  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1520 
1521  if (em->bm->totedgesel == 0) {
1522  continue;
1523  }
1524 
1525  BMEdge *eed;
1526  BMEdge **edarray;
1527  int edindex;
1528  BMIter iter;
1529  int totedgesel = 0;
1530 
1531  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1532  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1533  totedgesel++;
1534  }
1535  }
1536 
1537  edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
1538  edindex = 0;
1539 
1540  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1541  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1542  edarray[edindex] = eed;
1543  edindex++;
1544  }
1545  }
1546 
1547  if (is_ring) {
1548  for (edindex = 0; edindex < totedgesel; edindex += 1) {
1549  eed = edarray[edindex];
1550  walker_select(em, BMW_EDGERING, eed, true);
1551  }
1553  }
1554  else {
1555  for (edindex = 0; edindex < totedgesel; edindex += 1) {
1556  eed = edarray[edindex];
1557  bool non_manifold = BM_edge_face_count_is_over(eed, 2);
1558  if (non_manifold) {
1559  walker_select(em, BMW_EDGELOOP_NONMANIFOLD, eed, true);
1560  }
1561  else {
1562  walker_select(em, BMW_EDGELOOP, eed, true);
1563  }
1564  }
1566  }
1567  MEM_freeN(edarray);
1568  // if (EM_texFaceCheck())
1569 
1572  }
1573  MEM_freeN(objects);
1574 
1575  return OPERATOR_FINISHED;
1576 }
1577 
1579 {
1580  /* identifiers */
1581  ot->name = "Multi Select Loops";
1582  ot->idname = "MESH_OT_loop_multi_select";
1583  ot->description = "Select a loop of connected edges by connection type";
1584 
1585  /* api callbacks */
1588 
1589  /* flags */
1591 
1592  /* properties */
1593  RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1594 }
1595 
1598 /* -------------------------------------------------------------------- */
1602 static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1603 {
1604  if (select_clear) {
1606  }
1607 
1608  walker_select(em, BMW_FACELOOP, eed, select);
1609 }
1610 
1611 static void mouse_mesh_loop_edge_ring(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1612 {
1613  if (select_clear) {
1615  }
1616 
1617  walker_select(em, BMW_EDGERING, eed, select);
1618 }
1619 
1621  BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle)
1622 {
1623  bool edge_boundary = false;
1624  bool non_manifold = BM_edge_face_count_is_over(eed, 2);
1625 
1626  /* Cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY. */
1627  if (select_cycle && BM_edge_is_boundary(eed)) {
1628  int count_by_select[2];
1629 
1630  /* If the loops selected toggle the boundaries. */
1631  walker_select_count(em, BMW_EDGELOOP, eed, count_by_select);
1632  if (count_by_select[!select] == 0) {
1633  edge_boundary = true;
1634 
1635  /* If the boundaries selected, toggle back to the loop. */
1636  walker_select_count(em, BMW_EDGEBOUNDARY, eed, count_by_select);
1637  if (count_by_select[!select] == 0) {
1638  edge_boundary = false;
1639  }
1640  }
1641  }
1642 
1643  if (select_clear) {
1645  }
1646 
1647  if (edge_boundary) {
1649  }
1650  else if (non_manifold) {
1652  }
1653  else {
1654  walker_select(em, BMW_EDGELOOP, eed, select);
1655  }
1656 }
1657 
1658 static bool mouse_mesh_loop(
1659  bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
1660 {
1661  Base *basact = NULL;
1662  BMVert *eve = NULL;
1663  BMEdge *eed = NULL;
1664  BMFace *efa = NULL;
1665 
1666  ViewContext vc;
1667  BMEditMesh *em;
1668  bool select = true;
1669  bool select_clear = false;
1670  bool select_cycle = true;
1671  float mvalf[2];
1672 
1673  em_setup_viewcontext(C, &vc);
1674  mvalf[0] = (float)(vc.mval[0] = mval[0]);
1675  mvalf[1] = (float)(vc.mval[1] = mval[1]);
1676 
1677  BMEditMesh *em_original = vc.em;
1678  const short selectmode = em_original->selectmode;
1679  em_original->selectmode = SCE_SELECT_EDGE;
1680 
1681  uint bases_len;
1682  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
1683 
1684  {
1685  int base_index = -1;
1686  if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) {
1687  basact = bases[base_index];
1689  em = vc.em;
1690  }
1691  else {
1692  em = NULL;
1693  }
1694  }
1695 
1696  em_original->selectmode = selectmode;
1697 
1698  if (em == NULL || eed == NULL) {
1699  MEM_freeN(bases);
1700  return false;
1701  }
1702 
1703  if (extend == false && deselect == false && toggle == false) {
1704  select_clear = true;
1705  }
1706 
1707  if (extend) {
1708  select = true;
1709  }
1710  else if (deselect) {
1711  select = false;
1712  }
1713  else if (select_clear || (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0)) {
1714  select = true;
1715  }
1716  else if (toggle) {
1717  select = false;
1718  select_cycle = false;
1719  }
1720 
1721  if (select_clear) {
1722  for (uint base_index = 0; base_index < bases_len; base_index++) {
1723  Base *base_iter = bases[base_index];
1724  Object *ob_iter = base_iter->object;
1725  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
1726 
1727  if (em_iter->bm->totvertsel == 0) {
1728  continue;
1729  }
1730 
1731  if (em_iter == em) {
1732  continue;
1733  }
1734 
1737  }
1738  }
1739 
1740  if (em->selectmode & SCE_SELECT_FACE) {
1741  mouse_mesh_loop_face(em, eed, select, select_clear);
1742  }
1743  else {
1744  if (ring) {
1745  mouse_mesh_loop_edge_ring(em, eed, select, select_clear);
1746  }
1747  else {
1748  mouse_mesh_loop_edge(em, eed, select, select_clear, select_cycle);
1749  }
1750  }
1751 
1753 
1754  /* sets as active, useful for other tools */
1755  if (select) {
1756  if (em->selectmode & SCE_SELECT_VERTEX) {
1757  /* Find nearest vert from mouse
1758  * (initialize to large values in case only one vertex can be projected) */
1759  float v1_co[2], v2_co[2];
1760  float length_1 = FLT_MAX;
1761  float length_2 = FLT_MAX;
1762 
1763  /* We can't be sure this has already been set... */
1765 
1767  V3D_PROJ_RET_OK) {
1768  length_1 = len_squared_v2v2(mvalf, v1_co);
1769  }
1770 
1772  V3D_PROJ_RET_OK) {
1773  length_2 = len_squared_v2v2(mvalf, v2_co);
1774  }
1775 #if 0
1776  printf("mouse to v1: %f\nmouse to v2: %f\n",
1777  len_squared_v2v2(mvalf, v1_co),
1778  len_squared_v2v2(mvalf, v2_co));
1779 #endif
1780  BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2);
1781  }
1782  else if (em->selectmode & SCE_SELECT_EDGE) {
1783  BM_select_history_store(em->bm, eed);
1784  }
1785  else if (em->selectmode & SCE_SELECT_FACE) {
1786  /* Select the face of eed which is the nearest of mouse. */
1787  BMFace *f;
1788  BMIter iterf;
1789  float best_dist = FLT_MAX;
1790  efa = NULL;
1791 
1792  /* We can't be sure this has already been set... */
1794 
1795  BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) {
1797  float cent[3];
1798  float co[2], tdist;
1799 
1800  BM_face_calc_center_median(f, cent);
1802  V3D_PROJ_RET_OK) {
1803  tdist = len_squared_v2v2(mvalf, co);
1804  if (tdist < best_dist) {
1805  /* printf("Best face: %p (%f)\n", f, tdist);*/
1806  best_dist = tdist;
1807  efa = f;
1808  }
1809  }
1810  }
1811  }
1812  if (efa) {
1813  BM_mesh_active_face_set(em->bm, efa);
1814  BM_select_history_store(em->bm, efa);
1815  }
1816  }
1817  }
1818 
1819  MEM_freeN(bases);
1820 
1823 
1824  return true;
1825 }
1826 
1827 static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1828 {
1829 
1831 
1832  if (mouse_mesh_loop(C,
1833  event->mval,
1834  RNA_boolean_get(op->ptr, "extend"),
1835  RNA_boolean_get(op->ptr, "deselect"),
1836  RNA_boolean_get(op->ptr, "toggle"),
1837  RNA_boolean_get(op->ptr, "ring"))) {
1838  return OPERATOR_FINISHED;
1839  }
1840  return OPERATOR_CANCELLED;
1841 }
1842 
1844 {
1845  /* identifiers */
1846  ot->name = "Loop Select";
1847  ot->idname = "MESH_OT_loop_select";
1848  ot->description = "Select a loop of connected edges";
1849 
1850  /* api callbacks */
1853 
1854  /* flags */
1855  ot->flag = OPTYPE_UNDO;
1856 
1857  /* properties */
1858  RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
1859  RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1860  RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1861  RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
1862 }
1863 
1865 {
1866  /* description */
1867  ot->name = "Edge Ring Select";
1868  ot->idname = "MESH_OT_edgering_select";
1869  ot->description = "Select an edge ring";
1870 
1871  /* callbacks */
1874 
1875  /* flags */
1876  ot->flag = OPTYPE_UNDO;
1877 
1878  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1879  RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1880  RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1881  RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
1882 }
1883 
1886 /* -------------------------------------------------------------------- */
1891 {
1892  ViewLayer *view_layer = CTX_data_view_layer(C);
1893  int action = RNA_enum_get(op->ptr, "action");
1894 
1895  uint objects_len = 0;
1897  view_layer, CTX_wm_view3d(C), &objects_len);
1898 
1899  if (action == SEL_TOGGLE) {
1900  action = SEL_SELECT;
1901  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1902  Object *obedit = objects[ob_index];
1903  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1904  if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) {
1905  action = SEL_DESELECT;
1906  break;
1907  }
1908  }
1909  }
1910 
1911  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1912  Object *obedit = objects[ob_index];
1913  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1914  switch (action) {
1915  case SEL_SELECT:
1917  break;
1918  case SEL_DESELECT:
1920  break;
1921  case SEL_INVERT:
1922  EDBM_select_swap(em);
1924  break;
1925  }
1928  }
1929 
1930  MEM_freeN(objects);
1931 
1932  return OPERATOR_FINISHED;
1933 }
1934 
1936 {
1937  /* identifiers */
1938  ot->name = "(De)select All";
1939  ot->idname = "MESH_OT_select_all";
1940  ot->description = "(De)select all vertices, edges or faces";
1941 
1942  /* api callbacks */
1945 
1946  /* flags */
1948 
1950 }
1951 
1954 /* -------------------------------------------------------------------- */
1959 {
1960  ViewLayer *view_layer = CTX_data_view_layer(C);
1961  uint objects_len = 0;
1963  view_layer, CTX_wm_view3d(C), &objects_len);
1964 
1965  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1966  Object *obedit = objects[ob_index];
1967  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1968 
1969  if (!EDBM_select_interior_faces(em)) {
1970  continue;
1971  }
1972 
1975  }
1976  MEM_freeN(objects);
1977 
1978  return OPERATOR_FINISHED;
1979 }
1980 
1982 {
1983  /* identifiers */
1984  ot->name = "Select Interior Faces";
1985  ot->idname = "MESH_OT_select_interior_faces";
1986  ot->description = "Select faces where all edges have more than 2 face users";
1987 
1988  /* api callbacks */
1991 
1992  /* flags */
1994 }
1995 
1998 /* -------------------------------------------------------------------- */
2005 bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
2006 {
2007  ViewContext vc;
2008 
2009  int base_index_active = -1;
2010  BMVert *eve = NULL;
2011  BMEdge *eed = NULL;
2012  BMFace *efa = NULL;
2013 
2014  /* setup view context for argument to callbacks */
2015  em_setup_viewcontext(C, &vc);
2016  vc.mval[0] = mval[0];
2017  vc.mval[1] = mval[1];
2018 
2019  uint bases_len = 0;
2020  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
2021 
2022  bool ok = false;
2023 
2024  if (unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa)) {
2025  Base *basact = bases[base_index_active];
2027 
2028  /* Deselect everything */
2029  if (extend == false && deselect == false && toggle == false) {
2030  for (uint base_index = 0; base_index < bases_len; base_index++) {
2031  Base *base_iter = bases[base_index];
2032  Object *ob_iter = base_iter->object;
2034  if (basact->object != ob_iter) {
2037  }
2038  }
2039  }
2040 
2041  if (efa) {
2042  if (extend) {
2043  /* set the last selected face */
2044  BM_mesh_active_face_set(vc.em->bm, efa);
2045 
2046  /* Work-around: deselect first, so we can guarantee it will */
2047  /* be active even if it was already selected */
2048  BM_select_history_remove(vc.em->bm, efa);
2049  BM_face_select_set(vc.em->bm, efa, false);
2050  BM_select_history_store(vc.em->bm, efa);
2051  BM_face_select_set(vc.em->bm, efa, true);
2052  }
2053  else if (deselect) {
2054  BM_select_history_remove(vc.em->bm, efa);
2055  BM_face_select_set(vc.em->bm, efa, false);
2056  }
2057  else {
2058  /* set the last selected face */
2059  BM_mesh_active_face_set(vc.em->bm, efa);
2060 
2061  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2062  BM_select_history_store(vc.em->bm, efa);
2063  BM_face_select_set(vc.em->bm, efa, true);
2064  }
2065  else if (toggle) {
2066  BM_select_history_remove(vc.em->bm, efa);
2067  BM_face_select_set(vc.em->bm, efa, false);
2068  }
2069  }
2070  }
2071  else if (eed) {
2072  if (extend) {
2073  /* Work-around: deselect first, so we can guarantee it will */
2074  /* be active even if it was already selected */
2075  BM_select_history_remove(vc.em->bm, eed);
2076  BM_edge_select_set(vc.em->bm, eed, false);
2077  BM_select_history_store(vc.em->bm, eed);
2078  BM_edge_select_set(vc.em->bm, eed, true);
2079  }
2080  else if (deselect) {
2081  BM_select_history_remove(vc.em->bm, eed);
2082  BM_edge_select_set(vc.em->bm, eed, false);
2083  }
2084  else {
2085  if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2086  BM_select_history_store(vc.em->bm, eed);
2087  BM_edge_select_set(vc.em->bm, eed, true);
2088  }
2089  else if (toggle) {
2090  BM_select_history_remove(vc.em->bm, eed);
2091  BM_edge_select_set(vc.em->bm, eed, false);
2092  }
2093  }
2094  }
2095  else if (eve) {
2096  if (extend) {
2097  /* Work-around: deselect first, so we can guarantee it will */
2098  /* be active even if it was already selected */
2099  BM_select_history_remove(vc.em->bm, eve);
2100  BM_vert_select_set(vc.em->bm, eve, false);
2101  BM_select_history_store(vc.em->bm, eve);
2102  BM_vert_select_set(vc.em->bm, eve, true);
2103  }
2104  else if (deselect) {
2105  BM_select_history_remove(vc.em->bm, eve);
2106  BM_vert_select_set(vc.em->bm, eve, false);
2107  }
2108  else {
2109  if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
2110  BM_select_history_store(vc.em->bm, eve);
2111  BM_vert_select_set(vc.em->bm, eve, true);
2112  }
2113  else if (toggle) {
2114  BM_select_history_remove(vc.em->bm, eve);
2115  BM_vert_select_set(vc.em->bm, eve, false);
2116  }
2117  }
2118  }
2119 
2121 
2122  if (efa) {
2123  /* Change active material on object. */
2124  if (efa->mat_nr != vc.obedit->actcol - 1) {
2125  vc.obedit->actcol = efa->mat_nr + 1;
2126  vc.em->mat_nr = efa->mat_nr;
2128  }
2129 
2130  /* Change active face-map on object. */
2131  if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) {
2132  const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP);
2133  if (cd_fmap_offset != -1) {
2134  int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset));
2135  if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) {
2136  map = -1;
2137  }
2138  map += 1;
2139  if (map != vc.obedit->actfmap) {
2140  /* We may want to add notifiers later,
2141  * currently select update handles redraw. */
2142  vc.obedit->actfmap = map;
2143  }
2144  }
2145  }
2146  }
2147 
2148  /* Changing active object is handy since it allows us to
2149  * switch UV layers, vgroups for eg. */
2150  if (vc.view_layer->basact != basact) {
2151  ED_object_base_activate(C, basact);
2152  }
2153 
2156 
2157  ok = true;
2158  }
2159 
2160  MEM_freeN(bases);
2161 
2162  return ok;
2163 }
2164 
2167 /* -------------------------------------------------------------------- */
2172 {
2173  BMEditSelection *ese, *nextese;
2174 
2175  if (!(em->selectmode & SCE_SELECT_VERTEX)) {
2176  ese = em->bm->selected.first;
2177  while (ese) {
2178  nextese = ese->next;
2179  if (ese->htype == BM_VERT) {
2180  BLI_freelinkN(&(em->bm->selected), ese);
2181  }
2182  ese = nextese;
2183  }
2184  }
2185  if (!(em->selectmode & SCE_SELECT_EDGE)) {
2186  ese = em->bm->selected.first;
2187  while (ese) {
2188  nextese = ese->next;
2189  if (ese->htype == BM_EDGE) {
2190  BLI_freelinkN(&(em->bm->selected), ese);
2191  }
2192  ese = nextese;
2193  }
2194  }
2195  if (!(em->selectmode & SCE_SELECT_FACE)) {
2196  ese = em->bm->selected.first;
2197  while (ese) {
2198  nextese = ese->next;
2199  if (ese->htype == BM_FACE) {
2200  BLI_freelinkN(&(em->bm->selected), ese);
2201  }
2202  ese = nextese;
2203  }
2204  }
2205 }
2206 
2207 /* when switching select mode, makes sure selection is consistent for editing */
2208 /* also for paranoia checks to make sure edge or face mode works */
2210 {
2211  BMVert *eve;
2212  BMEdge *eed;
2213  BMFace *efa;
2214  BMIter iter;
2215 
2216  em->bm->selectmode = em->selectmode;
2217 
2218  /* strip BMEditSelections from em->selected that are not relevant to new mode */
2220 
2221  if (em->bm->totvertsel == 0 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
2222  return;
2223  }
2224 
2225  if (em->selectmode & SCE_SELECT_VERTEX) {
2226  if (em->bm->totvertsel) {
2227  EDBM_select_flush(em);
2228  }
2229  }
2230  else if (em->selectmode & SCE_SELECT_EDGE) {
2231  /* deselect vertices, and select again based on edge select */
2232  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2233  BM_vert_select_set(em->bm, eve, false);
2234  }
2235 
2236  if (em->bm->totedgesel) {
2237  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2238  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2239  BM_edge_select_set(em->bm, eed, true);
2240  }
2241  }
2242 
2243  /* selects faces based on edge status */
2245  }
2246  }
2247  else if (em->selectmode & SCE_SELECT_FACE) {
2248  /* Deselect edges, and select again based on face select. */
2249  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2250  BM_edge_select_set(em->bm, eed, false);
2251  }
2252 
2253  if (em->bm->totfacesel) {
2254  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2255  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2256  BM_face_select_set(em->bm, efa, true);
2257  }
2258  }
2259  }
2260  }
2261 }
2262 
2278  const short selectmode_old,
2279  const short selectmode_new)
2280 {
2281  BMesh *bm = em->bm;
2282 
2283  BMVert *eve;
2284  BMEdge *eed;
2285  BMFace *efa;
2286  BMIter iter;
2287 
2288  /* first tag-to-select, then select --- this avoids a feedback loop */
2289 
2290  /* Have to find out what the selection-mode was previously. */
2291  if (selectmode_old == SCE_SELECT_VERTEX) {
2292  if (bm->totvertsel == 0) {
2293  /* pass */
2294  }
2295  else if (selectmode_new == SCE_SELECT_EDGE) {
2296  /* flush up (vert -> edge) */
2297 
2298  /* select all edges associated with every selected vert */
2299  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2301  }
2302 
2303  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2304  if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
2305  BM_edge_select_set(bm, eed, true);
2306  }
2307  }
2308  }
2309  else if (selectmode_new == SCE_SELECT_FACE) {
2310  /* flush up (vert -> face) */
2311 
2312  /* select all faces associated with every selected vert */
2313  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2315  }
2316 
2317  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2318  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2319  BM_face_select_set(bm, efa, true);
2320  }
2321  }
2322  }
2323  }
2324  else if (selectmode_old == SCE_SELECT_EDGE) {
2325  if (bm->totedgesel == 0) {
2326  /* pass */
2327  }
2328  else if (selectmode_new == SCE_SELECT_FACE) {
2329  /* flush up (edge -> face) */
2330 
2331  /* select all faces associated with every selected edge */
2332  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2334  }
2335 
2336  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2337  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2338  BM_face_select_set(bm, efa, true);
2339  }
2340  }
2341  }
2342  else if (selectmode_new == SCE_SELECT_VERTEX) {
2343  /* flush down (edge -> vert) */
2344 
2345  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2346  if (!BM_vert_is_all_edge_flag_test(eve, BM_ELEM_SELECT, true)) {
2347  BM_vert_select_set(bm, eve, false);
2348  }
2349  }
2350  /* deselect edges without both verts selected */
2352  }
2353  }
2354  else if (selectmode_old == SCE_SELECT_FACE) {
2355  if (bm->totfacesel == 0) {
2356  /* pass */
2357  }
2358  else if (selectmode_new == SCE_SELECT_EDGE) {
2359  /* flush down (face -> edge) */
2360 
2361  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2362  if (!BM_edge_is_all_face_flag_test(eed, BM_ELEM_SELECT, true)) {
2363  BM_edge_select_set(bm, eed, false);
2364  }
2365  }
2366  /* Deselect faces without edges selected. */
2368  }
2369  else if (selectmode_new == SCE_SELECT_VERTEX) {
2370  /* flush down (face -> vert) */
2371 
2372  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2373  if (!BM_vert_is_all_face_flag_test(eve, BM_ELEM_SELECT, true)) {
2374  BM_vert_select_set(bm, eve, false);
2375  }
2376  }
2377  /* deselect faces without verts selected */
2379  }
2380  }
2381 }
2382 
2383 /* user facing function, does notification */
2385  const short selectmode_new,
2386  const int action,
2387  const bool use_extend,
2388  const bool use_expand)
2389 {
2391  ViewLayer *view_layer = CTX_data_view_layer(C);
2393  Object *obedit = CTX_data_edit_object(C);
2394  BMEditMesh *em = NULL;
2395  bool ret = false;
2396 
2397  if (obedit && obedit->type == OB_MESH) {
2398  em = BKE_editmesh_from_object(obedit);
2399  }
2400 
2401  if (em == NULL) {
2402  return ret;
2403  }
2404 
2405  bool only_update = false;
2406  switch (action) {
2407  case -1:
2408  /* already set */
2409  break;
2410  case 0: /* disable */
2411  /* check we have something to do */
2412  if ((em->selectmode & selectmode_new) == 0) {
2413  only_update = true;
2414  break;
2415  }
2416  em->selectmode &= ~selectmode_new;
2417  break;
2418  case 1: /* enable */
2419  /* check we have something to do */
2420  if ((em->selectmode & selectmode_new) != 0) {
2421  only_update = true;
2422  break;
2423  }
2424  em->selectmode |= selectmode_new;
2425  break;
2426  case 2: /* toggle */
2427  /* can't disable this flag if its the only one set */
2428  if (em->selectmode == selectmode_new) {
2429  only_update = true;
2430  break;
2431  }
2432  em->selectmode ^= selectmode_new;
2433  break;
2434  default:
2435  BLI_assert(0);
2436  break;
2437  }
2438 
2439  uint objects_len = 0;
2441  view_layer, CTX_wm_view3d(C), &objects_len);
2442 
2443  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2444  Object *ob_iter = objects[ob_index];
2445  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2446  if (em_iter != em) {
2447  em_iter->selectmode = em->selectmode;
2448  }
2449  }
2450 
2451  if (only_update) {
2452  MEM_freeN(objects);
2453  return false;
2454  }
2455 
2456  if (use_extend == 0 || em->selectmode == 0) {
2457  if (use_expand) {
2458  const short selmode_max = highest_order_bit_s(ts->selectmode);
2459  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2460  Object *ob_iter = objects[ob_index];
2461  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2462  EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new);
2463  }
2464  }
2465  }
2466 
2467  switch (selectmode_new) {
2468  case SCE_SELECT_VERTEX:
2469  if (use_extend == 0 || em->selectmode == 0) {
2471  }
2472  ret = true;
2473  break;
2474  case SCE_SELECT_EDGE:
2475  if (use_extend == 0 || em->selectmode == 0) {
2477  }
2478  ret = true;
2479  break;
2480  case SCE_SELECT_FACE:
2481  if (use_extend == 0 || em->selectmode == 0) {
2483  }
2484  ret = true;
2485  break;
2486  default:
2487  BLI_assert(0);
2488  break;
2489  }
2490 
2491  if (ret == true) {
2492  ts->selectmode = em->selectmode;
2493  em = NULL;
2494  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2495  Object *ob_iter = objects[ob_index];
2496  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2497  em_iter->selectmode = ts->selectmode;
2498  EDBM_selectmode_set(em_iter);
2501  }
2504  }
2505 
2506  MEM_freeN(objects);
2507  return ret;
2508 }
2509 
2510 bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
2511 {
2512  BLI_assert(selectmode != 0);
2513  bool changed = false;
2514 
2515  {
2516  Object *obedit = CTX_data_edit_object(C);
2517  BMEditMesh *em = NULL;
2518  if (obedit && obedit->type == OB_MESH) {
2519  em = BKE_editmesh_from_object(obedit);
2520  }
2521  if (em == NULL) {
2522  return changed;
2523  }
2524  }
2525 
2526  ViewLayer *view_layer = CTX_data_view_layer(C);
2529 
2530  if (ts->selectmode != selectmode) {
2531  ts->selectmode = selectmode;
2532  changed = true;
2533  }
2534 
2535  uint objects_len = 0;
2537  view_layer, CTX_wm_view3d(C), &objects_len);
2538 
2539  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2540  Object *ob_iter = objects[ob_index];
2541  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2542  if (em_iter->selectmode != ts->selectmode) {
2543  em_iter->selectmode = ts->selectmode;
2544  EDBM_selectmode_set(em_iter);
2547  changed = true;
2548  }
2549  }
2550  MEM_freeN(objects);
2551 
2552  if (changed) {
2555  }
2556  return changed;
2557 }
2558 
2566  BMEditMesh *em,
2567  const short selectmode_disable,
2568  const short selectmode_fallback)
2569 {
2570  /* note essential, but switch out of vertex mode since the
2571  * selected regions wont be nicely isolated after flushing */
2572  if (em->selectmode & selectmode_disable) {
2573  if (em->selectmode == selectmode_disable) {
2574  em->selectmode = selectmode_fallback;
2575  }
2576  else {
2577  em->selectmode &= ~selectmode_disable;
2578  }
2580  EDBM_selectmode_set(em);
2581 
2583 
2584  return true;
2585  }
2586  return false;
2587 }
2588 
2591 /* -------------------------------------------------------------------- */
2595 bool EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select)
2596 {
2597  BMIter iter;
2598  BMFace *efa;
2599  bool changed = false;
2600 
2601  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2602  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2603  continue;
2604  }
2605  if (efa->mat_nr == index) {
2606  changed = true;
2607  BM_face_select_set(em->bm, efa, select);
2608  }
2609  }
2610  return changed;
2611 }
2612 
2613 void EDBM_select_toggle_all(BMEditMesh *em) /* exported for UV */
2614 {
2615  if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) {
2617  }
2618  else {
2620  }
2621 }
2622 
2623 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
2624 {
2625  BMIter iter;
2626  BMVert *eve;
2627  BMEdge *eed;
2628  BMFace *efa;
2629 
2630  if (em->bm->selectmode & SCE_SELECT_VERTEX) {
2631  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2632  if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2633  continue;
2634  }
2636  }
2637  }
2638  else if (em->selectmode & SCE_SELECT_EDGE) {
2639  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2640  if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2641  continue;
2642  }
2644  }
2645  }
2646  else {
2647  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2648  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2649  continue;
2650  }
2652  }
2653  }
2654 }
2655 
2656 bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
2657 {
2658  bool changed_multi = false;
2659  for (uint base_index = 0; base_index < bases_len; base_index++) {
2660  Base *base_iter = bases[base_index];
2661  Object *ob_iter = base_iter->object;
2662  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2663 
2664  if (em_iter->bm->totvertsel == 0) {
2665  continue;
2666  }
2667 
2670  changed_multi = true;
2671  }
2672  return changed_multi;
2673 }
2674 
2676 {
2678  ViewContext vc;
2680  uint bases_len = 0;
2682  vc.view_layer, vc.v3d, &bases_len);
2683  bool changed_multi = EDBM_mesh_deselect_all_multi_ex(bases, bases_len);
2684  MEM_freeN(bases);
2685  return changed_multi;
2686 }
2687 
2689  struct Base **bases,
2690  const uint bases_len,
2691  const short selectmode_disable,
2692  const short selectmode_fallback)
2693 {
2694  bool changed_multi = false;
2695  for (uint base_index = 0; base_index < bases_len; base_index++) {
2696  Base *base_iter = bases[base_index];
2697  Object *ob_iter = base_iter->object;
2698  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2699 
2700  if (EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback)) {
2701  changed_multi = true;
2702  }
2703  }
2704  return changed_multi;
2705 }
2706 
2708  const short selectmode_disable,
2709  const short selectmode_fallback)
2710 {
2713  ViewContext vc;
2715  uint bases_len = 0;
2717  vc.view_layer, NULL, &bases_len);
2718  bool changed_multi = EDBM_selectmode_disable_multi_ex(
2719  scene, bases, bases_len, selectmode_disable, selectmode_fallback);
2720  MEM_freeN(bases);
2721  return changed_multi;
2722 }
2723 
2726 /* -------------------------------------------------------------------- */
2738 struct BMFaceLink {
2739  struct BMFaceLink *next, *prev;
2741  float area;
2742 };
2743 
2745 {
2746  if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
2747  return false;
2748  }
2749  return true;
2750 }
2752  int face_index,
2753  BMLoop *r_l_pair[2])
2754 {
2755 
2756  BMLoop *l_iter = e->l;
2757  int loop_index = 0;
2758  do {
2759  BMFace *f = l_iter->f;
2760  int i = BM_elem_index_get(f);
2761  if (!ELEM(i, -1, face_index)) {
2762  if (loop_index == 2) {
2763  return false;
2764  }
2765  r_l_pair[loop_index++] = l_iter;
2766  }
2767  } while ((l_iter = l_iter->radial_next) != e->l);
2768  return (loop_index == 2);
2769 }
2770 
2775 static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_lengths)
2776 {
2777  /* Dividing by the area is important so larger face groups (which will become the outer shell)
2778  * aren't detected as having a high cost. */
2779  float area = 0.0f;
2780  float cost = 0.0f;
2781  bool found = false;
2782  LISTBASE_FOREACH (struct BMFaceLink *, f_link, ls) {
2783  BMFace *f = f_link->face;
2784  area += f_link->area;
2785  int i = BM_elem_index_get(f);
2786  BLI_assert(i != -1);
2787  BMLoop *l_iter, *l_first;
2788  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2789  do {
2790  if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG)) {
2791  float cost_test = 0.0f;
2792  int cost_count = 0;
2793  /* All other faces. */
2794  BMLoop *l_radial_iter = l_iter;
2795  do {
2796  int i_other = BM_elem_index_get(l_radial_iter->f);
2797  if (!ELEM(i_other, -1, i)) {
2798  float angle = angle_normalized_v3v3(f->no, l_radial_iter->f->no);
2799  /* Ignore face direction since in the case on non-manifold faces connecting edges,
2800  * the face flipping may not be meaningful. */
2801  if (angle > DEG2RADF(90)) {
2802  angle = DEG2RADF(180) - angle;
2803  }
2804  /* Avoid calculating it inline, pass in pre-calculated edge lengths. */
2805 #if 0
2806  cost_test += BM_edge_calc_length(l_iter->e) * angle;
2807 #else
2808  BLI_assert(edge_lengths[BM_elem_index_get(l_iter->e)] != -1.0f);
2809  cost_test += edge_lengths[BM_elem_index_get(l_iter->e)] * angle;
2810 #endif
2811  cost_count += 1;
2812  }
2813  } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
2814 
2815  if (cost_count >= 2) {
2816  cost += cost_test;
2817  found = true;
2818  }
2819  }
2820  } while ((l_iter = l_iter->next) != l_first);
2821  }
2822  return found ? cost / area : FLT_MAX;
2823 }
2824 
2826 {
2827  BMesh *bm = em->bm;
2828  BMIter iter;
2829  bool changed = false;
2830 
2831  float *edge_lengths = MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__);
2832 
2833  {
2834  bool has_nonmanifold = false;
2835  BMEdge *e;
2836  int i;
2837  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
2838  const bool is_over = BM_edge_face_count_is_over(e, 2);
2839  if (is_over) {
2841  has_nonmanifold = true;
2842  edge_lengths[i] = BM_edge_calc_length(e);
2843  }
2844  else {
2846  edge_lengths[i] = -1.0;
2847  }
2848 
2849  BM_elem_index_set(e, i); /* set_inline */
2850  }
2852 
2853  if (has_nonmanifold == false) {
2854  MEM_freeN(edge_lengths);
2855  return false;
2856  }
2857  }
2858 
2859  /* group vars */
2860  int *fgroup_array;
2861  int(*fgroup_index)[2];
2862  int fgroup_len;
2863 
2864  fgroup_array = MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__);
2865  fgroup_len = BM_mesh_calc_face_groups(
2866  bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, NULL, NULL, 0, BM_EDGE);
2867 
2868  int *fgroup_recalc_stack = MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__);
2869  STACK_DECLARE(fgroup_recalc_stack);
2870  STACK_INIT(fgroup_recalc_stack, fgroup_len);
2871 
2873 
2874  {
2875  BMFace *f;
2876  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2877  BM_elem_index_set(f, -1); /* set_dirty! */
2878  }
2879  }
2881 
2882  ListBase *fgroup_listbase = MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__);
2883  struct BMFaceLink *f_link_array = MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__);
2884 
2885  for (int i = 0; i < fgroup_len; i++) {
2886  const int fg_sta = fgroup_index[i][0];
2887  const int fg_len = fgroup_index[i][1];
2888  for (int j = 0; j < fg_len; j++) {
2889  const int face_index = fgroup_array[fg_sta + j];
2890  BMFace *f = BM_face_at_index(bm, face_index);
2891  BM_elem_index_set(f, i);
2892 
2893  struct BMFaceLink *f_link = &f_link_array[face_index];
2894  f_link->face = f;
2895  f_link->area = BM_face_calc_area(f);
2896  BLI_addtail(&fgroup_listbase[i], f_link);
2897  }
2898  }
2899 
2900  MEM_freeN(fgroup_array);
2901  MEM_freeN(fgroup_index);
2902 
2903  Heap *fgroup_heap = BLI_heap_new_ex(fgroup_len);
2904  HeapNode **fgroup_table = MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__);
2905  bool *fgroup_dirty = MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__);
2906 
2907  for (int i = 0; i < fgroup_len; i++) {
2908  const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
2909  if (cost != FLT_MAX) {
2910  fgroup_table[i] = BLI_heap_insert(fgroup_heap, -cost, POINTER_FROM_INT(i));
2911  }
2912  else {
2913  fgroup_table[i] = NULL;
2914  }
2915  }
2916 
2917  /* Avoid re-running cost calculations for large face-groups which will end up forming the
2918  * outer shell and not be considered interior.
2919  * As these face groups become increasingly bigger - their chance of being considered
2920  * interior reduces as does the time to calculate their cost.
2921  *
2922  * This delays recalculating them until they are considered can dates to remove
2923  * which becomes less and less likely as they increase in area. */
2924 
2925 #define USE_DELAY_FACE_GROUP_COST_CALC
2926 
2927  while (true) {
2928 
2929 #if defined(USE_DELAY_FACE_GROUP_COST_CALC)
2930  while (!BLI_heap_is_empty(fgroup_heap)) {
2931  HeapNode *node_min = BLI_heap_top(fgroup_heap);
2932  const int i = POINTER_AS_INT(BLI_heap_node_ptr(node_min));
2933  if (fgroup_dirty[i]) {
2934  const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
2935  if (cost != FLT_MAX) {
2936  /* The cost may have improves (we may be able to skip this),
2937  * however the cost should _never_ make this a choice. */
2938  BLI_assert(-BLI_heap_node_value(node_min) >= cost);
2939  BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
2940  }
2941  else {
2942  BLI_heap_remove(fgroup_heap, fgroup_table[i]);
2943  fgroup_table[i] = NULL;
2944  }
2945  fgroup_dirty[i] = false;
2946  }
2947  else {
2948  break;
2949  }
2950  }
2951 #endif
2952 
2953  if (BLI_heap_is_empty(fgroup_heap)) {
2954  break;
2955  }
2956 
2957  const int i_min = POINTER_AS_INT(BLI_heap_pop_min(fgroup_heap));
2958  BLI_assert(fgroup_table[i_min] != NULL);
2959  BLI_assert(fgroup_dirty[i_min] == false);
2960  fgroup_table[i_min] = NULL;
2961  changed = true;
2962 
2963  struct BMFaceLink *f_link;
2964  while ((f_link = BLI_pophead(&fgroup_listbase[i_min]))) {
2965  BMFace *f = f_link->face;
2966  BM_face_select_set(bm, f, true);
2967  BM_elem_index_set(f, -1); /* set-dirty */
2968 
2969  BMLoop *l_iter, *l_first;
2970 
2971  /* Loop over edges face edges, merging groups which are no longer separated
2972  * by non-manifold edges (when manifold check ignores faces from this group). */
2973  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2974  do {
2975  BMLoop *l_pair[2];
2976  if (bm_interior_edge_is_manifold_except_face_index(l_iter->e, i_min, l_pair)) {
2978 
2979  int i_a = BM_elem_index_get(l_pair[0]->f);
2980  int i_b = BM_elem_index_get(l_pair[1]->f);
2981  if (i_a != i_b) {
2982  /* Only for predictable results that don't depend on the order of radial loops,
2983  * not essential. */
2984  if (i_a > i_b) {
2985  SWAP(int, i_a, i_b);
2986  }
2987 
2988  /* Merge the groups. */
2989  LISTBASE_FOREACH (LinkData *, n, &fgroup_listbase[i_b]) {
2990  BMFace *f_iter = n->data;
2991  BM_elem_index_set(f_iter, i_a);
2992  }
2993  BLI_movelisttolist(&fgroup_listbase[i_a], &fgroup_listbase[i_b]);
2994 
2995  /* This may have been added to 'fgroup_recalc_stack', instead of removing it,
2996  * just check the heap node isn't NULL before recalculating. */
2997  BLI_heap_remove(fgroup_heap, fgroup_table[i_b]);
2998  fgroup_table[i_b] = NULL;
2999  /* Keep the dirty flag as-is for 'i_b', because it may be in the 'fgroup_recalc_stack'
3000  * and we don't want to add it again.
3001  * Instead rely on the 'fgroup_table[i_b]' being NULL as a secondary check. */
3002 
3003  if (fgroup_dirty[i_a] == false) {
3004  BLI_assert(fgroup_table[i_a] != NULL);
3005  STACK_PUSH(fgroup_recalc_stack, i_a);
3006  fgroup_dirty[i_a] = true;
3007  }
3008  }
3009  }
3010 
3011  /* Mark all connected groups for re-calculation. */
3012  BMLoop *l_radial_iter = l_iter->radial_next;
3013  if (l_radial_iter != l_iter) {
3014  do {
3015  int i_other = BM_elem_index_get(l_radial_iter->f);
3016  if (!ELEM(i_other, -1, i_min)) {
3017  if ((fgroup_table[i_other] != NULL) && (fgroup_dirty[i_other] == false)) {
3018 #if !defined(USE_DELAY_FACE_GROUP_COST_CALC)
3019  STACK_PUSH(fgroup_recalc_stack, i_other);
3020 #endif
3021  fgroup_dirty[i_other] = true;
3022  }
3023  }
3024  } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
3025  }
3026 
3027  } while ((l_iter = l_iter->next) != l_first);
3028  }
3029 
3030  for (int index = 0; index < STACK_SIZE(fgroup_recalc_stack); index++) {
3031  const int i = fgroup_recalc_stack[index];
3032  if (fgroup_table[i] != NULL && fgroup_dirty[i] == true) {
3033  /* First update edge tags. */
3034  const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
3035  if (cost != FLT_MAX) {
3036  BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
3037  }
3038  else {
3039  BLI_heap_remove(fgroup_heap, fgroup_table[i]);
3040  fgroup_table[i] = NULL;
3041  }
3042  }
3043  fgroup_dirty[i] = false;
3044  }
3045  STACK_CLEAR(fgroup_recalc_stack);
3046  }
3047 
3048  MEM_freeN(edge_lengths);
3049  MEM_freeN(f_link_array);
3050  MEM_freeN(fgroup_listbase);
3051  MEM_freeN(fgroup_recalc_stack);
3052  MEM_freeN(fgroup_table);
3053  MEM_freeN(fgroup_dirty);
3054 
3055  BLI_heap_free(fgroup_heap, NULL);
3056 
3057  return changed;
3058 }
3059 
3062 /* -------------------------------------------------------------------- */
3068 /* so we can have last-used default depend on selection mode (rare exception!) */
3069 #define USE_LINKED_SELECT_DEFAULT_HACK
3070 
3071 struct DelimitData {
3072  int cd_loop_type;
3073  int cd_loop_offset;
3074 };
3075 
3077  int delimit,
3078  const struct DelimitData *delimit_data)
3079 {
3080  BLI_assert(delimit);
3081 
3082  if (delimit & BMO_DELIM_SEAM) {
3084  return true;
3085  }
3086  }
3087 
3088  if (delimit & BMO_DELIM_SHARP) {
3089  if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
3090  return true;
3091  }
3092  }
3093 
3094  if (delimit & BMO_DELIM_NORMAL) {
3095  if (!BM_edge_is_contiguous(e)) {
3096  return true;
3097  }
3098  }
3099 
3100  if (delimit & BMO_DELIM_MATERIAL) {
3101  if (e->l && e->l->radial_next != e->l) {
3102  const short mat_nr = e->l->f->mat_nr;
3103  BMLoop *l_iter = e->l->radial_next;
3104  do {
3105  if (l_iter->f->mat_nr != mat_nr) {
3106  return true;
3107  }
3108  } while ((l_iter = l_iter->radial_next) != e->l);
3109  }
3110  }
3111 
3112  if (delimit & BMO_DELIM_UV) {
3114  e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) {
3115  return true;
3116  }
3117  }
3118 
3119  return false;
3120 }
3121 
3122 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3127 static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode)
3128 {
3129  static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
3130  int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
3131  char *delimit_last = &delimit_last_store[delimit_last_index];
3132  PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit");
3133  int delimit;
3134 
3135  if (RNA_property_is_set(op->ptr, prop_delimit)) {
3136  delimit = RNA_property_enum_get(op->ptr, prop_delimit);
3137  *delimit_last = delimit;
3138  }
3139  else {
3140  delimit = *delimit_last;
3141  RNA_property_enum_set(op->ptr, prop_delimit, delimit);
3142  }
3143  return delimit;
3144 }
3145 #endif
3146 
3147 static void select_linked_delimit_validate(BMesh *bm, int *delimit)
3148 {
3149  if ((*delimit) & BMO_DELIM_UV) {
3151  (*delimit) &= ~BMO_DELIM_UV;
3152  }
3153  }
3154 }
3155 
3156 static void select_linked_delimit_begin(BMesh *bm, int delimit)
3157 {
3158  struct DelimitData delimit_data = {0};
3159 
3160  if (delimit & BMO_DELIM_UV) {
3161  delimit_data.cd_loop_type = CD_MLOOPUV;
3162  delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
3163  if (delimit_data.cd_loop_offset == -1) {
3164  delimit &= ~BMO_DELIM_UV;
3165  }
3166  }
3167 
3168  /* grr, shouldn't need to alloc BMO flags here */
3170 
3171  {
3172  BMIter iter;
3173  BMEdge *e;
3174 
3175  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
3176  const bool is_walk_ok = ((select_linked_delimit_test(e, delimit, &delimit_data) == false));
3177 
3178  BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
3179  }
3180  }
3181 }
3182 
3184 {
3185  BMesh *bm = em->bm;
3186 
3188 }
3189 
3191 {
3193  ViewLayer *view_layer = CTX_data_view_layer(C);
3194 
3195 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3196  const int delimit_init = select_linked_delimit_default_from_op(op,
3198 #else
3199  const int delimit_init = RNA_enum_get(op->ptr, "delimit");
3200 #endif
3201 
3202  uint objects_len = 0;
3204  view_layer, CTX_wm_view3d(C), &objects_len);
3205 
3206  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3207  Object *obedit = objects[ob_index];
3208 
3209  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3210  BMesh *bm = em->bm;
3211  BMIter iter;
3212  BMWalker walker;
3213 
3214  int delimit = delimit_init;
3215 
3217 
3218  if (delimit) {
3219  select_linked_delimit_begin(em->bm, delimit);
3220  }
3221 
3222  if (em->selectmode & SCE_SELECT_VERTEX) {
3223  BMVert *v;
3224 
3225  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3227  }
3228 
3229  /* exclude all delimited verts */
3230  if (delimit) {
3231  BMEdge *e;
3232  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3233  if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
3234  /* Check the edge for selected faces,
3235  * this supports stepping off isolated vertices which would otherwise be ignored. */
3239  }
3240  }
3241  }
3242  }
3243 
3244  BMW_init(&walker,
3245  em->bm,
3246  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3247  BMW_MASK_NOP,
3248  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3249  BMW_MASK_NOP,
3251  BMW_NIL_LAY);
3252 
3253  if (delimit) {
3254  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3256  BMElem *ele_walk;
3257  BMW_ITER (ele_walk, &walker, v) {
3258  if (ele_walk->head.htype == BM_LOOP) {
3259  BMVert *v_step = ((BMLoop *)ele_walk)->v;
3260  BM_vert_select_set(em->bm, v_step, true);
3262  }
3263  else {
3264  BMEdge *e_step = (BMEdge *)ele_walk;
3265  BLI_assert(ele_walk->head.htype == BM_EDGE);
3266  BM_edge_select_set(em->bm, e_step, true);
3269  }
3270  }
3271  }
3272  }
3273  }
3274  else {
3275  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3277  BMEdge *e_walk;
3278  BMW_ITER (e_walk, &walker, v) {
3279  BM_edge_select_set(em->bm, e_walk, true);
3281  }
3282  }
3283  }
3284  }
3285 
3286  BMW_end(&walker);
3287 
3289  }
3290  else if (em->selectmode & SCE_SELECT_EDGE) {
3291  BMEdge *e;
3292 
3293  if (delimit) {
3294  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3295  /* Check the edge for selected faces,
3296  * this supports stepping off isolated edges which would otherwise be ignored. */
3298  BM_ELEM_TAG,
3302  }
3303  }
3304  else {
3305  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3307  }
3308  }
3309 
3310  BMW_init(&walker,
3311  em->bm,
3312  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3313  BMW_MASK_NOP,
3314  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3315  BMW_MASK_NOP,
3317  BMW_NIL_LAY);
3318 
3319  if (delimit) {
3320  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3322  BMElem *ele_walk;
3323  BMW_ITER (ele_walk, &walker, e) {
3324  if (ele_walk->head.htype == BM_LOOP) {
3325  BMLoop *l_step = (BMLoop *)ele_walk;
3326  BM_edge_select_set(em->bm, l_step->e, true);
3327  BM_edge_select_set(em->bm, l_step->prev->e, true);
3329  }
3330  else {
3331  BMEdge *e_step = (BMEdge *)ele_walk;
3332  BLI_assert(ele_walk->head.htype == BM_EDGE);
3333  BM_edge_select_set(em->bm, e_step, true);
3335  }
3336  }
3337  }
3338  }
3339  }
3340  else {
3341  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3343  BMEdge *e_walk;
3344  BMW_ITER (e_walk, &walker, e) {
3345  BM_edge_select_set(em->bm, e_walk, true);
3347  }
3348  }
3349  }
3350  }
3351 
3352  BMW_end(&walker);
3353 
3355  }
3356  else {
3357  BMFace *f;
3358 
3359  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
3361  }
3362 
3363  BMW_init(&walker,
3364  bm,
3365  BMW_ISLAND,
3366  BMW_MASK_NOP,
3367  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3368  BMW_MASK_NOP,
3370  BMW_NIL_LAY);
3371 
3372  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
3373  if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
3374  BMFace *f_walk;
3375  BMW_ITER (f_walk, &walker, f) {
3376  BM_face_select_set(bm, f_walk, true);
3378  }
3379  }
3380  }
3381 
3382  BMW_end(&walker);
3383  }
3384 
3385  if (delimit) {
3387  }
3388 
3391  }
3392 
3393  MEM_freeN(objects);
3394 
3395  return OPERATOR_FINISHED;
3396 }
3397 
3399 {
3400  PropertyRNA *prop;
3401 
3402  /* identifiers */
3403  ot->name = "Select Linked All";
3404  ot->idname = "MESH_OT_select_linked";
3405  ot->description = "Select all vertices connected to the current selection";
3406 
3407  /* api callbacks */
3410 
3411  /* flags */
3413 
3414  prop = RNA_def_enum_flag(ot->srna,
3415  "delimit",
3418  "Delimit",
3419  "Delimit selected region");
3420 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3422 #else
3423  UNUSED_VARS(prop);
3424 #endif
3425 }
3426 
3429 /* -------------------------------------------------------------------- */
3434 
3435 static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
3436 {
3437  BMesh *bm = em->bm;
3438  BMWalker walker;
3439 
3441 
3442  if (delimit) {
3443  select_linked_delimit_begin(bm, delimit);
3444  }
3445 
3446  /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
3447 
3448  if (ele->head.htype == BM_VERT) {
3449  BMVert *eve = (BMVert *)ele;
3450 
3451  BMW_init(&walker,
3452  bm,
3453  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3454  BMW_MASK_NOP,
3455  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3456  BMW_MASK_NOP,
3458  BMW_NIL_LAY);
3459 
3460  if (delimit) {
3461  BMElem *ele_walk;
3462  BMW_ITER (ele_walk, &walker, eve) {
3463  if (ele_walk->head.htype == BM_LOOP) {
3464  BMVert *v_step = ((BMLoop *)ele_walk)->v;
3465  BM_vert_select_set(bm, v_step, sel);
3466  }
3467  else {
3468  BMEdge *e_step = (BMEdge *)ele_walk;
3469  BLI_assert(ele_walk->head.htype == BM_EDGE);
3470  BM_edge_select_set(bm, e_step, sel);
3471  }
3472  }
3473  }
3474  else {
3475  BMEdge *e_walk;
3476  BMW_ITER (e_walk, &walker, eve) {
3477  BM_edge_select_set(bm, e_walk, sel);
3478  }
3479  }
3480 
3481  BMW_end(&walker);
3482 
3484  }
3485  else if (ele->head.htype == BM_EDGE) {
3486  BMEdge *eed = (BMEdge *)ele;
3487 
3488  BMW_init(&walker,
3489  bm,
3490  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3491  BMW_MASK_NOP,
3492  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3493  BMW_MASK_NOP,
3495  BMW_NIL_LAY);
3496 
3497  if (delimit) {
3498  BMElem *ele_walk;
3499  BMW_ITER (ele_walk, &walker, eed) {
3500  if (ele_walk->head.htype == BM_LOOP) {
3501  BMEdge *e_step = ((BMLoop *)ele_walk)->e;
3502  BM_edge_select_set(bm, e_step, sel);
3503  }
3504  else {
3505  BMEdge *e_step = (BMEdge *)ele_walk;
3506  BLI_assert(ele_walk->head.htype == BM_EDGE);
3507  BM_edge_select_set(bm, e_step, sel);
3508  }
3509  }
3510  }
3511  else {
3512  BMEdge *e_walk;
3513  BMW_ITER (e_walk, &walker, eed) {
3514  BM_edge_select_set(bm, e_walk, sel);
3515  }
3516  }
3517 
3518  BMW_end(&walker);
3519 
3521  }
3522  else if (ele->head.htype == BM_FACE) {
3523  BMFace *efa = (BMFace *)ele;
3524 
3525  BMW_init(&walker,
3526  bm,
3527  BMW_ISLAND,
3528  BMW_MASK_NOP,
3529  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3530  BMW_MASK_NOP,
3532  BMW_NIL_LAY);
3533 
3534  {
3535  BMFace *f_walk;
3536  BMW_ITER (f_walk, &walker, efa) {
3537  BM_face_select_set(bm, f_walk, sel);
3539  }
3540  }
3541 
3542  BMW_end(&walker);
3543  }
3544 
3545  if (delimit) {
3547  }
3548 }
3549 
3551 {
3552  ViewContext vc;
3553  Base *basact = NULL;
3554  BMVert *eve;
3555  BMEdge *eed;
3556  BMFace *efa;
3557  const bool sel = !RNA_boolean_get(op->ptr, "deselect");
3558  int index;
3559 
3560  if (RNA_struct_property_is_set(op->ptr, "index")) {
3561  return edbm_select_linked_pick_exec(C, op);
3562  }
3563 
3564  /* unified_finednearest needs ogl */
3566 
3567  /* setup view context for argument to callbacks */
3568  em_setup_viewcontext(C, &vc);
3569 
3570  uint bases_len;
3571  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
3572 
3573  {
3574  bool has_edges = false;
3575  for (uint base_index = 0; base_index < bases_len; base_index++) {
3576  Object *ob_iter = bases[base_index]->object;
3577  ED_view3d_viewcontext_init_object(&vc, ob_iter);
3578  if (vc.em->bm->totedge) {
3579  has_edges = true;
3580  }
3581  }
3582  if (has_edges == false) {
3583  MEM_freeN(bases);
3584  return OPERATOR_CANCELLED;
3585  }
3586  }
3587 
3588  vc.mval[0] = event->mval[0];
3589  vc.mval[1] = event->mval[1];
3590 
3591  /* return warning! */
3592  {
3593  int base_index = -1;
3594  const bool ok = unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa);
3595  if (!ok) {
3596  MEM_freeN(bases);
3597  return OPERATOR_CANCELLED;
3598  }
3599  basact = bases[base_index];
3600  }
3601 
3603  BMEditMesh *em = vc.em;
3604  BMesh *bm = em->bm;
3605 
3606 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3608 #else
3609  int delimit = RNA_enum_get(op->ptr, "delimit");
3610 #endif
3611 
3612  BMElem *ele = EDBM_elem_from_selectmode(em, eve, eed, efa);
3613 
3614  edbm_select_linked_pick_ex(em, ele, sel, delimit);
3615 
3616  /* To support redo. */
3617  {
3618  /* Note that the `base_index` can't be used as the index depends on the 3D Viewport
3619  * which might not be available on redo. */
3621  int object_index;
3622  index = EDBM_elem_to_index_any_multi(vc.view_layer, em, ele, &object_index);
3623  BLI_assert(object_index >= 0);
3624  RNA_int_set(op->ptr, "object_index", object_index);
3625  RNA_int_set(op->ptr, "index", index);
3626  }
3627 
3630 
3631  MEM_freeN(bases);
3632  return OPERATOR_FINISHED;
3633 }
3634 
3636 {
3637  Object *obedit = NULL;
3638  BMElem *ele;
3639 
3640  {
3641  ViewLayer *view_layer = CTX_data_view_layer(C);
3642  const int object_index = RNA_int_get(op->ptr, "object_index");
3643  const int index = RNA_int_get(op->ptr, "index");
3644  ele = EDBM_elem_from_index_any_multi(view_layer, object_index, index, &obedit);
3645  }
3646 
3647  if (ele == NULL) {
3648  return OPERATOR_CANCELLED;
3649  }
3650 
3651  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3652  const bool sel = !RNA_boolean_get(op->ptr, "deselect");
3653 
3654 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3655  int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
3656 #else
3657  int delimit = RNA_enum_get(op->ptr, "delimit");
3658 #endif
3659 
3660  edbm_select_linked_pick_ex(em, ele, sel, delimit);
3661 
3664 
3665  return OPERATOR_FINISHED;
3666 }
3667 
3669 {
3670  PropertyRNA *prop;
3671 
3672  /* identifiers */
3673  ot->name = "Select Linked";
3674  ot->idname = "MESH_OT_select_linked_pick";
3675  ot->description = "(De)select all vertices linked to the edge under the mouse cursor";
3676 
3677  /* api callbacks */
3681 
3682  /* flags */
3684 
3685  RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
3686  prop = RNA_def_enum_flag(ot->srna,
3687  "delimit",
3690  "Delimit",
3691  "Delimit selected region");
3692 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3694 #endif
3695 
3696  /* use for redo */
3697  prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
3699  prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
3701 }
3702 
3705 /* -------------------------------------------------------------------- */
3710 {
3711  ViewLayer *view_layer = CTX_data_view_layer(C);
3712  uint objects_len = 0;
3713  const bool extend = RNA_boolean_get(op->ptr, "extend");
3714  const int numverts = RNA_int_get(op->ptr, "number");
3715  const int type = RNA_enum_get(op->ptr, "type");
3717  view_layer, CTX_wm_view3d(C), &objects_len);
3718 
3719  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3720  Object *obedit = objects[ob_index];
3721  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3722  BMFace *efa;
3723  BMIter iter;
3724 
3725  if (!extend) {
3727  }
3728 
3729  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3730  bool select;
3731 
3732  switch (type) {
3733  case 0:
3734  select = (efa->len < numverts);
3735  break;
3736  case 1:
3737  select = (efa->len == numverts);
3738  break;
3739  case 2:
3740  select = (efa->len > numverts);
3741  break;
3742  case 3:
3743  select = (efa->len != numverts);
3744  break;
3745  default:
3746  BLI_assert(0);
3747  select = false;
3748  break;
3749  }
3750 
3751  if (select) {
3752  BM_face_select_set(em->bm, efa, true);
3753  }
3754  }
3755 
3757 
3760  }
3761 
3762  MEM_freeN(objects);
3763  return OPERATOR_FINISHED;
3764 }
3765 
3767 {
3768  static const EnumPropertyItem type_items[] = {
3769  {0, "LESS", 0, "Less Than", ""},
3770  {1, "EQUAL", 0, "Equal To", ""},
3771  {2, "GREATER", 0, "Greater Than", ""},
3772  {3, "NOTEQUAL", 0, "Not Equal To", ""},
3773  {0, NULL, 0, NULL, NULL},
3774  };
3775 
3776  /* identifiers */
3777  ot->name = "Select Faces by Sides";
3778  ot->description = "Select vertices or faces by the number of polygon sides";
3779  ot->idname = "MESH_OT_select_face_by_sides";
3780 
3781  /* api callbacks */
3784 
3785  /* flags */
3787 
3788  /* properties */
3789  RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX);
3790  RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make");
3791  RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
3792 }
3793 
3796 /* -------------------------------------------------------------------- */
3801 {
3802  ViewLayer *view_layer = CTX_data_view_layer(C);
3803  const bool extend = RNA_boolean_get(op->ptr, "extend");
3804 
3805  uint objects_len = 0;
3807  view_layer, CTX_wm_view3d(C), &objects_len);
3808 
3809  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3810  Object *obedit = objects[ob_index];
3811  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3812  BMesh *bm = em->bm;
3813  BMIter iter;
3814 
3815  if (!extend) {
3817  }
3818 
3819  if (em->selectmode & SCE_SELECT_VERTEX) {
3820  BMVert *eve;
3821  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
3822  if (!eve->e) {
3823  BM_vert_select_set(bm, eve, true);
3824  }
3825  }
3826  }
3827 
3828  if (em->selectmode & SCE_SELECT_EDGE) {
3829  BMEdge *eed;
3830  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
3831  if (BM_edge_is_wire(eed)) {
3832  BM_edge_select_set(bm, eed, true);
3833  }
3834  }
3835  }
3836 
3837  if (em->selectmode & SCE_SELECT_FACE) {
3838  BMFace *efa;
3839  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
3840  BMIter liter;
3841  BMLoop *l;
3842  bool is_loose = true;
3843  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3844  if (!BM_edge_is_boundary(l->e)) {
3845  is_loose = false;
3846  break;
3847  }
3848  }
3849  if (is_loose) {
3850  BM_face_select_set(bm, efa, true);
3851  }
3852  }
3853  }
3854 
3856 
3859  }
3860 
3861  MEM_freeN(objects);
3862 
3863  return OPERATOR_FINISHED;
3864 }
3865 
3867 {
3868  /* identifiers */
3869  ot->name = "Select Loose Geometry";
3870  ot->description = "Select loose geometry based on the selection mode";
3871  ot->idname = "MESH_OT_select_loose";
3872 
3873  /* api callbacks */
3876 
3877  /* flags */
3879 
3880  /* props */
3881  RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
3882 }
3883 
3886 /* -------------------------------------------------------------------- */
3891 {
3892  ViewLayer *view_layer = CTX_data_view_layer(C);
3893  const int axis_flag = RNA_enum_get(op->ptr, "axis");
3894  const bool extend = RNA_boolean_get(op->ptr, "extend");
3895  Object *obedit_active = CTX_data_edit_object(C);
3896  BMEditMesh *em_active = BKE_editmesh_from_object(obedit_active);
3897  const int select_mode = em_active->bm->selectmode;
3898  int tot_mirr = 0, tot_fail = 0;
3899 
3900  uint objects_len = 0;
3902  view_layer, CTX_wm_view3d(C), &objects_len);
3903 
3904  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3905  Object *obedit = objects[ob_index];
3906  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3907 
3908  if (em->bm->totvertsel == 0) {
3909  continue;
3910  }
3911 
3912  int tot_mirr_iter = 0, tot_fail_iter = 0;
3913 
3914  for (int axis = 0; axis < 3; axis++) {
3915  if ((1 << axis) & axis_flag) {
3916  EDBM_select_mirrored(em, obedit->data, axis, extend, &tot_mirr_iter, &tot_fail_iter);
3917  }
3918  }
3919 
3920  if (tot_mirr_iter) {
3922 
3925  }
3926 
3927  tot_fail += tot_fail_iter;
3928  tot_mirr += tot_mirr_iter;
3929  }
3930  MEM_freeN(objects);
3931 
3932  if (tot_mirr || tot_fail) {
3933  ED_mesh_report_mirror_ex(op, tot_mirr, tot_fail, select_mode);
3934  }
3935  return OPERATOR_FINISHED;
3936 }
3937 
3939 {
3940  /* identifiers */
3941  ot->name = "Select Mirror";
3942  ot->description = "Select mesh items at mirrored locations";
3943  ot->idname = "MESH_OT_select_mirror";
3944 
3945  /* api callbacks */
3948 
3949  /* flags */
3951 
3952  /* props */
3953  RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", "");
3954 
3955  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
3956 }
3957 
3960 /* -------------------------------------------------------------------- */
3965 {
3966  ViewLayer *view_layer = CTX_data_view_layer(C);
3967  const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
3968 
3969  uint objects_len = 0;
3971  view_layer, CTX_wm_view3d(C), &objects_len);
3972  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3973  Object *obedit = objects[ob_index];
3974  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3975  BMesh *bm = em->bm;
3976 
3977  if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) {
3978  continue;
3979  }
3980 
3981  EDBM_select_more(em, use_face_step);
3984  }
3985 
3986  MEM_freeN(objects);
3987  return OPERATOR_FINISHED;
3988 }
3989 
3991 {
3992  /* identifiers */
3993  ot->name = "Select More";
3994  ot->idname = "MESH_OT_select_more";
3995  ot->description = "Select more vertices, edges or faces connected to initial selection";
3996 
3997  /* api callbacks */
4000 
4001  /* flags */
4003 
4005  ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
4006 }
4007 
4010 /* -------------------------------------------------------------------- */
4015 {
4016  ViewLayer *view_layer = CTX_data_view_layer(C);
4017  const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
4018 
4019  uint objects_len = 0;
4021  view_layer, CTX_wm_view3d(C), &objects_len);
4022  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4023  Object *obedit = objects[ob_index];
4024  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4025  BMesh *bm = em->bm;
4026 
4027  if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) {
4028  continue;
4029  }
4030 
4031  EDBM_select_less(em, use_face_step);
4034  }
4035 
4036  MEM_freeN(objects);
4037  return OPERATOR_FINISHED;
4038 }
4039 
4041 {
4042  /* identifiers */
4043  ot->name = "Select Less";
4044  ot->idname = "MESH_OT_select_less";
4045  ot->description = "Deselect vertices, edges or faces at the boundary of each selection region";
4046 
4047  /* api callbacks */
4050 
4051  /* flags */
4053 
4055  ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
4056 }
4057 
4060 /* -------------------------------------------------------------------- */
4068 {
4069  BMIter viter;
4070  BMVert *v;
4071 
4072  BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
4073  BMIter eiter;
4074  BMEdge *e_other;
4075 
4076  BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) {
4077  if ((e_other != e) && BM_elem_flag_test(e_other, BM_ELEM_SELECT)) {
4078  return false;
4079  }
4080  }
4081  }
4082  return true;
4083 }
4084 
4085 /* Walk all reachable elements of the same type as h_act in breadth-first
4086  * order, starting from h_act. Deselects elements if the depth when they
4087  * are reached is not a multiple of "nth". */
4089  const struct CheckerIntervalParams *op_params,
4090  BMHeader *h_act)
4091 {
4092  BMElem *ele;
4093  BMesh *bm = em->bm;
4094  BMWalker walker;
4095  BMIter iter;
4096  int walktype = 0, itertype = 0, flushtype = 0;
4097  short mask_vert = 0, mask_edge = 0, mask_face = 0;
4098 
4099  /* No active element from which to start - nothing to do */
4100  if (h_act == NULL) {
4101  return;
4102  }
4103 
4104  /* Determine which type of iter, walker, and select flush to use
4105  * based on type of the elements being deselected */
4106  switch (h_act->htype) {
4107  case BM_VERT:
4108  itertype = BM_VERTS_OF_MESH;
4109  walktype = BMW_CONNECTED_VERTEX;
4110  flushtype = SCE_SELECT_VERTEX;
4111  mask_vert = BMO_ELE_TAG;
4112  break;
4113  case BM_EDGE:
4114  /* When an edge has no connected-selected edges,
4115  * use face-stepping (supports edge-rings) */
4116  itertype = BM_EDGES_OF_MESH;
4118  flushtype = SCE_SELECT_EDGE;
4119  mask_edge = BMO_ELE_TAG;
4120  break;
4121  case BM_FACE:
4122  itertype = BM_FACES_OF_MESH;
4123  walktype = BMW_ISLAND;
4124  flushtype = SCE_SELECT_FACE;
4125  mask_face = BMO_ELE_TAG;
4126  break;
4127  }
4128 
4129  /* grr, shouldn't need to alloc BMO flags here */
4131 
4132  /* Walker restrictions uses BMO flags, not header flags,
4133  * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */
4134  BMO_push(bm, NULL);
4135  BM_ITER_MESH (ele, &iter, bm, itertype) {
4136  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
4138  }
4139  }
4140 
4141  /* Walk over selected elements starting at active */
4142  BMW_init(&walker,
4143  bm,
4144  walktype,
4145  mask_vert,
4146  mask_edge,
4147  mask_face,
4148  BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
4149  BMW_NIL_LAY);
4150 
4151  /* use tag to avoid touching the same verts twice */
4152  BM_ITER_MESH (ele, &iter, bm, itertype) {
4154  }
4155 
4156  BLI_assert(walker.order == BMW_BREADTH_FIRST);
4157  for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
4158  if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
4159  /* Deselect elements that aren't at "nth" depth from active */
4160  const int depth = BMW_current_depth(&walker) - 1;
4161  if (!WM_operator_properties_checker_interval_test(op_params, depth)) {
4162  BM_elem_select_set(bm, ele, false);
4163  }
4165  }
4166  }
4167  BMW_end(&walker);
4168 
4169  BMO_pop(bm);
4170 
4171  /* Flush selection up */
4172  EDBM_selectmode_flush_ex(em, flushtype);
4173 }
4174 
4175 static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
4176 {
4177  BMIter iter;
4178  BMElem *ele;
4179 
4180  *r_eve = NULL;
4181  *r_eed = NULL;
4182  *r_efa = NULL;
4183 
4185  ele = BM_mesh_active_elem_get(em->bm);
4186 
4187  if (ele && BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
4188  switch (ele->head.htype) {
4189  case BM_VERT:
4190  *r_eve = (BMVert *)ele;
4191  return;
4192  case BM_EDGE:
4193  *r_eed = (BMEdge *)ele;
4194  return;
4195  case BM_FACE:
4196  *r_efa = (BMFace *)ele;
4197  return;
4198  }
4199  }
4200 
4201  if (em->selectmode & SCE_SELECT_VERTEX) {
4202  BMVert *v;
4203  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
4205  *r_eve = v;
4206  return;
4207  }
4208  }
4209  }
4210  else if (em->selectmode & SCE_SELECT_EDGE) {
4211  BMEdge *e;
4212  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
4214  *r_eed = e;
4215  return;
4216  }
4217  }
4218  }
4219  else if (em->selectmode & SCE_SELECT_FACE) {
4220  BMFace *f = BM_mesh_active_face_get(em->bm, true, false);
4221  if (f && BM_elem_flag_test(f, BM_ELEM_SELECT)) {
4222  *r_efa = f;
4223  return;
4224  }
4225  }
4226 }
4227 
4228 static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params)
4229 {
4230  BMVert *v;
4231  BMEdge *e;
4232  BMFace *f;
4233 
4234  deselect_nth_active(em, &v, &e, &f);
4235 
4236  if (v) {
4237  walker_deselect_nth(em, op_params, &v->head);
4238  return true;
4239  }
4240  if (e) {
4241  walker_deselect_nth(em, op_params, &e->head);
4242  return true;
4243  }
4244  if (f) {
4245  walker_deselect_nth(em, op_params, &f->head);
4246  return true;
4247  }
4248 
4249  return false;
4250 }
4251 
4253 {
4254  ViewLayer *view_layer = CTX_data_view_layer(C);
4255  struct CheckerIntervalParams op_params;
4257  bool found_active_elt = false;
4258 
4259  uint objects_len = 0;
4261  view_layer, CTX_wm_view3d(C), &objects_len);
4262 
4263  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4264  Object *obedit = objects[ob_index];
4265  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4266 
4267  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
4268  continue;
4269  }
4270 
4271  if (edbm_deselect_nth(em, &op_params) == true) {
4272  found_active_elt = true;
4273  EDBM_update_generic(obedit->data, false, false);
4274  }
4275  }
4276  MEM_freeN(objects);
4277 
4278  if (!found_active_elt) {
4279  BKE_report(op->reports, RPT_ERROR, "Mesh object(s) have no active vertex/edge/face");
4280  return OPERATOR_CANCELLED;
4281  }
4282 
4283  return OPERATOR_FINISHED;
4284 }
4285 
4287 {
4288  /* identifiers */
4289  ot->name = "Checker Deselect";
4290  ot->idname = "MESH_OT_select_nth";
4291  ot->description = "Deselect every Nth element starting from the active vertex, edge or face";
4292 
4293  /* api callbacks */
4296 
4297  /* flags */
4299 
4301 }
4302 
4304 {
4307 
4308  if (vc->obedit) {
4309  vc->em = BKE_editmesh_from_object(vc->obedit);
4310  }
4311 }
4312 
4315 /* -------------------------------------------------------------------- */
4320 {
4321  /* Find edges that have exactly two neighboring faces,
4322  * check the angle between those faces, and if angle is
4323  * small enough, select the edge
4324  */
4325  const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
4326 
4327  ViewLayer *view_layer = CTX_data_view_layer(C);
4328  uint objects_len = 0;
4330  view_layer, CTX_wm_view3d(C), &objects_len);
4331 
4332  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4333  Object *obedit = objects[ob_index];
4334  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4335  BMIter iter;
4336  BMEdge *e;
4337  BMLoop *l1, *l2;
4338 
4339  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
4340  if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false && BM_edge_loop_pair(e, &l1, &l2)) {
4341  /* edge has exactly two neighboring faces, check angle */
4342  const float angle_cos = dot_v3v3(l1->f->no, l2->f->no);
4343 
4344  if (angle_cos < angle_limit_cos) {
4345  BM_edge_select_set(em->bm, e, true);
4346  }
4347  }
4348  }
4349 
4350  if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
4351  /* Since we can't select individual edges, select faces connected to them. */
4353  }
4354  else {
4356  }
4359  }
4360  MEM_freeN(objects);
4361 
4362  return OPERATOR_FINISHED;
4363 }
4364 
4366 {
4367  PropertyRNA *prop;
4368 
4369  /* identifiers */
4370  ot->name = "Select Sharp Edges";
4371  ot->description = "Select all sharp enough edges";
4372  ot->idname = "MESH_OT_edges_select_sharp";
4373 
4374  /* api callbacks */
4377 
4378  /* flags */
4380 
4381  /* props */
4382  prop = RNA_def_float_rotation(ot->srna,
4383  "sharpness",
4384  0,
4385  NULL,
4386  DEG2RADF(0.01f),
4387  DEG2RADF(180.0f),
4388  "Sharpness",
4389  "",
4390  DEG2RADF(1.0f),
4391  DEG2RADF(180.0f));
4393 }
4394 
4397 /* -------------------------------------------------------------------- */
4402 {
4403  ViewLayer *view_layer = CTX_data_view_layer(C);
4404  uint objects_len = 0;
4406  view_layer, CTX_wm_view3d(C), &objects_len);
4407  const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
4408 
4409  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4410  Object *obedit = objects[ob_index];
4411  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4412  BMesh *bm = em->bm;
4413 
4414  if (bm->totfacesel == 0) {
4415  continue;
4416  }
4417 
4418  BLI_LINKSTACK_DECLARE(stack, BMFace *);
4419 
4420  BMIter iter, liter, liter2;
4421  BMFace *f;
4422  BMLoop *l, *l2;
4423 
4425 
4426  BLI_LINKSTACK_INIT(stack);
4427 
4428  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
4429  if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) ||
4430  (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) ||
4431  (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) {
4432  continue;
4433  }
4434 
4435  BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0);
4436 
4437  do {
4438  BM_face_select_set(bm, f, true);
4439 
4441 
4442  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
4443  BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
4444  float angle_cos;
4445 
4446  if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) ||
4448  continue;
4449  }
4450 
4451  angle_cos = dot_v3v3(f->no, l2->f->no);
4452 
4453  if (angle_cos > angle_limit_cos) {
4454  BLI_LINKSTACK_PUSH(stack, l2->f);
4455  }
4456  }
4457  }
4458  } while ((f = BLI_LINKSTACK_POP(stack)));
4459  }
4460 
4461  BLI_LINKSTACK_FREE(stack);
4462 
4465  }
4466  MEM_freeN(objects);
4467 
4468  return OPERATOR_FINISHED;
4469 }
4470 
4472 {
4473  PropertyRNA *prop;
4474 
4475  /* identifiers */
4476  ot->name = "Select Linked Flat Faces";
4477  ot->description = "Select linked faces by angle";
4478  ot->idname = "MESH_OT_faces_select_linked_flat";
4479 
4480  /* api callbacks */
4483 
4484  /* flags */
4486 
4487  /* props */
4488  prop = RNA_def_float_rotation(ot->srna,
4489  "sharpness",
4490  0,
4491  NULL,
4492  DEG2RADF(0.01f),
4493  DEG2RADF(180.0f),
4494  "Sharpness",
4495  "",
4496  DEG2RADF(1.0f),
4497  DEG2RADF(180.0f));
4499 }
4500 
4503 /* -------------------------------------------------------------------- */
4508 {
4509  const bool use_extend = RNA_boolean_get(op->ptr, "extend");
4510  const bool use_wire = RNA_boolean_get(op->ptr, "use_wire");
4511  const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
4512  const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face");
4513  const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous");
4514  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
4515 
4516  ViewLayer *view_layer = CTX_data_view_layer(C);
4517  uint objects_len = 0;
4519  view_layer, CTX_wm_view3d(C), &objects_len);
4520 
4521  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4522  Object *obedit = objects[ob_index];
4523  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4524  BMVert *v;
4525  BMEdge *e;
4526  BMIter iter;
4527 
4528  if (!use_extend) {
4530  }
4531 
4532  /* Selects isolated verts, and edges that do not have 2 neighboring
4533  * faces
4534  */
4535 
4536  if (em->selectmode == SCE_SELECT_FACE) {
4537  BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
4538  MEM_freeN(objects);
4539  return OPERATOR_CANCELLED;
4540  }
4541 
4542  if (use_verts) {
4543  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
4545  if (!BM_vert_is_manifold(v)) {
4546  BM_vert_select_set(em->bm, v, true);
4547  }
4548  }
4549  }
4550  }
4551 
4552  if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
4553  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
4555  if ((use_wire && BM_edge_is_wire(e)) || (use_boundary && BM_edge_is_boundary(e)) ||
4556  (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
4557  (use_multi_face && (BM_edge_face_count_is_over(e, 2)))) {
4558  /* check we never select perfect edge (in test above) */
4560 
4561  BM_edge_select_set(em->bm, e, true);
4562  }
4563  }
4564  }
4565  }
4566 
4569 
4571  }
4572  MEM_freeN(objects);
4573 
4574  return OPERATOR_FINISHED;
4575 }
4576 
4578 {
4579  /* identifiers */
4580  ot->name = "Select Non-Manifold";
4581  ot->description = "Select all non-manifold vertices or edges";
4582  ot->idname = "MESH_OT_select_non_manifold";
4583 
4584  /* api callbacks */
4587 
4588  /* flags */
4590 
4591  /* props */
4592  RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
4593  /* edges */
4594  RNA_def_boolean(ot->srna, "use_wire", true, "Wire", "Wire edges");
4595  RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", "Boundary edges");
4597  ot->srna, "use_multi_face", true, "Multiple Faces", "Edges shared by more than two faces");
4599  "use_non_contiguous",
4600  true,
4601  "Non Contiguous",
4602  "Edges between faces pointing in alternate directions");
4603  /* verts */
4605  ot->srna, "use_verts", true, "Vertices", "Vertices connecting multiple face regions");
4606 }
4607 
4610 /* -------------------------------------------------------------------- */
4615 {
4616  const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
4617  const float randfac = RNA_float_get(op->ptr, "ratio");
4619 
4620  ViewLayer *view_layer = CTX_data_view_layer(C);
4621 
4622  uint objects_len = 0;
4624  view_layer, CTX_wm_view3d(C), &objects_len);
4625  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4626  Object *obedit = objects[ob_index];
4627  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4628  BMIter iter;
4629  int seed_iter = seed;
4630 
4631  /* This gives a consistent result regardless of object order. */
4632  if (ob_index) {
4633  seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
4634  }
4635 
4636  if (em->selectmode & SCE_SELECT_VERTEX) {
4637  int elem_map_len = 0;
4638  BMVert **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totvert, __func__);
4639  BMVert *eve;
4640  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
4641  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
4642  elem_map[elem_map_len++] = eve;
4643  }
4644  }
4645 
4646  BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter);
4647  const int count_select = elem_map_len * randfac;
4648  for (int i = 0; i < count_select; i++) {
4649  BM_vert_select_set(em->bm, elem_map[i], select);
4650  }
4651  MEM_freeN(elem_map);
4652  }
4653  else if (em->selectmode & SCE_SELECT_EDGE) {
4654  int elem_map_len = 0;
4655  BMEdge **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totedge, __func__);
4656  BMEdge *eed;
4657  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
4658  if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
4659  elem_map[elem_map_len++] = eed;
4660  }
4661  }
4662  BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter);
4663  const int count_select = elem_map_len * randfac;
4664  for (int i = 0; i < count_select; i++) {
4665  BM_edge_select_set(em->bm, elem_map[i], select);
4666  }
4667  MEM_freeN(elem_map);
4668  }
4669  else {
4670  int elem_map_len = 0;
4671  BMFace **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totface, __func__);
4672  BMFace *efa;
4673  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4674  if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
4675  elem_map[elem_map_len++] = efa;
4676  }
4677  }
4678  BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter);
4679  const int count_select = elem_map_len * randfac;
4680  for (int i = 0; i < count_select; i++) {
4681  BM_face_select_set(em->bm, elem_map[i], select);
4682  }
4683  MEM_freeN(elem_map);
4684  }
4685 
4686  if (select) {
4687  /* was EDBM_select_flush, but it over select in edge/face mode */
4689  }
4690  else {
4691  EDBM_deselect_flush(em);
4692  }
4693 
4696  }
4697 
4698  MEM_freeN(objects);
4699  return OPERATOR_FINISHED;
4700 }
4701 
4703 {
4704  /* identifiers */
4705  ot->name = "Select Random";
4706  ot->description = "Randomly select vertices";
4707  ot->idname = "MESH_OT_select_random";
4708 
4709  /* api callbacks */
4712 
4713  /* flags */
4715 
4716  /* props */
4718 }
4719 
4722 /* -------------------------------------------------------------------- */
4727 {
4728  if (ED_operator_editmesh(C)) {
4729  Object *obedit = CTX_data_edit_object(C);
4730  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4731  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
4732 
4733  if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
4734  CTX_wm_operator_poll_msg_set(C, "Must be in vertex selection mode");
4735  }
4736  else if (BLI_listbase_is_empty(&obedit->defbase) || cd_dvert_offset == -1) {
4737  CTX_wm_operator_poll_msg_set(C, "No weights/vertex groups on object");
4738  }
4739  else {
4740  return true;
4741  }
4742  }
4743  return false;
4744 }
4745 
4747 {
4748  const bool extend = RNA_boolean_get(op->ptr, "extend");
4749  ViewLayer *view_layer = CTX_data_view_layer(C);
4750 
4751  uint objects_len = 0;
4753  view_layer, CTX_wm_view3d(C), &objects_len);
4754 
4755  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4756  Object *obedit = objects[ob_index];
4757  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4758 
4759  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
4760 
4761  if (cd_dvert_offset == -1) {
4762  continue;
4763  }
4764 
4765  BMVert *eve;
4766  BMIter iter;
4767 
4768  bool changed = false;
4769 
4770  if (!extend) {
4771  if (em->bm->totvertsel) {
4773  changed = true;
4774  }
4775  }
4776 
4777  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
4778  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
4779  MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
4780  /* no dv or dv set with no weight */
4781  if (ELEM(NULL, dv, dv->dw)) {
4782  BM_vert_select_set(em->bm, eve, true);
4783  changed = true;
4784  }
4785  }
4786  }
4787 
4788  if (changed) {
4792  }
4793  }
4794  MEM_freeN(objects);
4795  return OPERATOR_FINISHED;
4796 }
4797 
4799 {
4800  /* identifiers */
4801  ot->name = "Select Ungrouped";
4802  ot->idname = "MESH_OT_select_ungrouped";
4803  ot->description = "Select vertices without a group";
4804 
4805  /* api callbacks */
4808 
4809  /* flags */
4811 
4812  RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
4813 }
4814 
4817 /* -------------------------------------------------------------------- */
4821 enum {
4825 };
4826 
4828 {
4830  ViewLayer *view_layer = CTX_data_view_layer(C);
4831  Object *obedit = CTX_data_edit_object(C);
4832  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4833  BMVert *v_act = BM_mesh_active_vert_get(em->bm);
4834  const int orientation = RNA_enum_get(op->ptr, "orientation");
4835  const int axis = RNA_enum_get(op->ptr, "axis");
4836  const int sign = RNA_enum_get(op->ptr, "sign");
4837 
4838  if (v_act == NULL) {
4839  BKE_report(
4840  op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)");
4841  return OPERATOR_CANCELLED;
4842  }
4843 
4844  const float limit = RNA_float_get(op->ptr, "threshold");
4845 
4846  float value;
4847  float axis_mat[3][3];
4848 
4849  /* 3D view variables may be NULL, (no need to check in poll function). */
4851  C, axis_mat, scene, CTX_wm_region_view3d(C), obedit, obedit, orientation, V3D_AROUND_ACTIVE);
4852 
4853  const float *axis_vector = axis_mat[axis];
4854 
4855  {
4856  float vertex_world[3];
4857  mul_v3_m4v3(vertex_world, obedit->obmat, v_act->co);
4858  value = dot_v3v3(axis_vector, vertex_world);
4859  }
4860 
4861  if (sign == SELECT_AXIS_NEG) {
4862  value += limit;
4863  }
4864  else if (sign == SELECT_AXIS_POS) {
4865  value -= limit;
4866  }
4867 
4868  uint objects_len = 0;
4870  view_layer, CTX_wm_view3d(C), &objects_len);
4871  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4872  Object *obedit_iter = objects[ob_index];
4873  BMEditMesh *em_iter = BKE_editmesh_from_object(obedit_iter);
4874  BMesh *bm = em_iter->bm;
4875 
4876  if (bm->totvert == bm->totvertsel) {
4877  continue;
4878  }
4879 
4880  BMIter iter;
4881  BMVert *v;
4882  bool changed = false;
4883 
4884  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
4886  float v_iter_world[3];
4887  mul_v3_m4v3(v_iter_world, obedit_iter->obmat, v->co);
4888  const float value_iter = dot_v3v3(axis_vector, v_iter_world);
4889  switch (sign) {
4890  case SELECT_AXIS_ALIGN:
4891  if (fabsf(value_iter - value) < limit) {
4892  BM_vert_select_set(bm, v, true);
4893  changed = true;
4894  }
4895  break;
4896  case SELECT_AXIS_NEG:
4897  if (value_iter < value) {
4898  BM_vert_select_set(bm, v, true);
4899  changed = true;
4900  }
4901  break;
4902  case SELECT_AXIS_POS:
4903  if (value_iter > value) {
4904  BM_vert_select_set(bm, v, true);
4905  changed = true;
4906  }
4907  break;
4908  }
4909  }
4910  }
4911  if (changed) {
4912  EDBM_selectmode_flush(em_iter);
4913  WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data);
4914  DEG_id_tag_update(obedit_iter->data, ID_RECALC_SELECT);
4915  }
4916  }
4917  MEM_freeN(objects);
4918  return OPERATOR_FINISHED;
4919 }
4920 
4922 {
4923  static const EnumPropertyItem axis_sign_items[] = {
4924  {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""},
4925  {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""},
4926  {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""},
4927  {0, NULL, 0, NULL, NULL},
4928  };
4929 
4930  /* identifiers */
4931  ot->name = "Select Axis";
4932  ot->description = "Select all data in the mesh on a single axis";
4933  ot->idname = "MESH_OT_select_axis";
4934 
4935  /* api callbacks */
4938 
4939  /* flags */
4941 
4942  /* properties */
4943  RNA_def_enum(ot->srna,
4944  "orientation",
4947  "Axis Mode",
4948  "Axis orientation");
4949  RNA_def_enum(ot->srna, "sign", axis_sign_items, SELECT_AXIS_POS, "Axis Sign", "Side to select");
4950  RNA_def_enum(ot->srna,
4951  "axis",
4953  0,
4954  "Axis",
4955  "Select the axis to compare each vertex on");
4956  RNA_def_float(
4957  ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f);
4958 }
4959 
4962 /* -------------------------------------------------------------------- */
4967 {
4968  ViewLayer *view_layer = CTX_data_view_layer(C);
4969  uint objects_len = 0;
4971  view_layer, CTX_wm_view3d(C), &objects_len);
4972  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4973  Object *obedit = objects[ob_index];
4974  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4975 
4976  if (em->bm->totfacesel == 0) {
4977  continue;
4978  }
4979  BMFace *f;
4980  BMEdge *e;
4981  BMIter iter;
4982 
4984 
4985  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
4986  BMLoop *l1, *l2;
4987  BMIter liter1, liter2;
4988 
4989  BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
4990  int tot = 0, totsel = 0;
4991 
4992  BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
4993  tot++;
4994  totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
4995  }
4996 
4997  if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) {
4999  }
5000  }
5001  }
5002 
5004 
5005  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
5007  BM_edge_select_set(em->bm, e, true);
5008  }
5009  }
5010 
5011  /* If in face-only select mode, switch to edge select mode so that
5012  * an edge-only selection is not inconsistent state */
5013  if (em->selectmode == SCE_SELECT_FACE) {
5015  EDBM_selectmode_set(em);
5017  }
5018 
5021  }
5022  MEM_freeN(objects);
5023 
5024  return OPERATOR_FINISHED;
5025 }
5026 
5028 {
5029  /* identifiers */
5030  ot->name = "Select Boundary Loop";
5031  ot->idname = "MESH_OT_region_to_loop";
5032  ot->description = "Select boundary edges around the selected faces";
5033 
5034  /* api callbacks */
5037 
5038  /* flags */
5040 }
5041 
5044 /* -------------------------------------------------------------------- */
5048 static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ***region_out)
5049 {
5050  BMFace **region = NULL;
5051  BMFace **stack = NULL;
5052  BLI_array_declare(region);
5053  BLI_array_declare(stack);
5054  BMFace *f;
5055 
5056  BLI_array_append(stack, l->f);
5057  BLI_gset_insert(visit_face_set, l->f);
5058 
5059  while (BLI_array_len(stack) > 0) {
5060  BMIter liter1, liter2;
5061  BMLoop *l1, *l2;
5062 
5063  f = BLI_array_pop(stack);
5064  BLI_array_append(region, f);
5065 
5066  BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
5067  if (BM_elem_flag_test(l1->e, flag)) {
5068  continue;
5069  }
5070 
5071  BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
5072  /* avoids finding same region twice
5073  * (otherwise) the logic works fine without */
5074  if (BM_elem_flag_test(l2->f, BM_ELEM_TAG)) {
5075  continue;
5076  }
5077 
5078  if (BLI_gset_add(visit_face_set, l2->f)) {
5079  BLI_array_append(stack, l2->f);
5080  }
5081  }
5082  }
5083  }
5084 
5085  BLI_array_free(stack);
5086 
5087  *region_out = region;
5088  return BLI_array_len(region);
5089 }
5090 
5091 static int verg_radial(const void *va, const void *vb)
5092 {
5093  const BMEdge *e_a = *((const BMEdge **)va);
5094  const BMEdge *e_b = *((const BMEdge **)vb);
5095 
5096  const int a = BM_edge_face_count(e_a);
5097  const int b = BM_edge_face_count(e_b);
5098 
5099  if (a > b) {
5100  return -1;
5101  }
5102  if (a < b) {
5103  return 1;
5104  }
5105  return 0;
5106 }
5107 
5114 static int loop_find_regions(BMEditMesh *em, const bool selbigger)
5115 {
5116  GSet *visit_face_set;
5117  BMIter iter;
5118  const int edges_len = em->bm->totedgesel;
5119  BMEdge *e, **edges;
5120  int count = 0, i;
5121 
5122  visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len);
5123  edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
5124 
5125  i = 0;
5126  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
5128  edges[i++] = e;
5130  }
5131  else {
5133  }
5134  }
5135 
5136  /* sort edges by radial cycle length */
5137  qsort(edges, edges_len, sizeof(*edges), verg_radial);
5138 
5139  for (i = 0; i < edges_len; i++) {
5140  BMIter liter;
5141  BMLoop *l;
5142  BMFace **region = NULL, **region_out;
5143  int c, tot = 0;
5144 
5145  e = edges[i];
5146 
5147  if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
5148  continue;
5149  }
5150 
5151  BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
5152  if (BLI_gset_haskey(visit_face_set, l->f)) {
5153  continue;
5154  }
5155 
5156  c = loop_find_region(l, BM_ELEM_SELECT, visit_face_set, &region_out);
5157 
5158  if (!region || (selbigger ? c >= tot : c < tot)) {
5159  /* this region is the best seen so far */
5160  tot = c;
5161  if (region) {
5162  /* free the previous best */
5163  MEM_freeN(region);
5164  }
5165  /* track the current region as the new best */
5166  region = region_out;
5167  }
5168  else {
5169  /* this region is not as good as best so far, just free it */
5170  MEM_freeN(region_out);
5171  }
5172  }
5173 
5174  if (region) {
5175  int j;
5176 
5177  for (j = 0; j < tot; j++) {
5178  BM_elem_flag_enable(region[j], BM_ELEM_TAG);
5179  BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) {
5181  }
5182  }
5183 
5184  count += tot;
5185 
5186  MEM_freeN(region);
5187  }
5188  }
5189 
5190  MEM_freeN(edges);
5191  BLI_gset_free(visit_face_set, NULL);
5192 
5193  return count;
5194 }
5195 
5197 {
5198  const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger");
5199 
5200  ViewLayer *view_layer = CTX_data_view_layer(C);
5201  uint objects_len = 0;
5203  view_layer, CTX_wm_view3d(C), &objects_len);
5204  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5205  Object *obedit = objects[ob_index];
5206  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5207 
5208  if (em->bm->totedgesel == 0) {
5209  continue;
5210  }
5211 
5212  BMIter iter;
5213  BMFace *f;
5214 
5215  /* find the set of regions with smallest number of total faces */
5217  const int a = loop_find_regions(em, select_bigger);
5218  const int b = loop_find_regions(em, !select_bigger);
5219 
5221  loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger);
5222 
5224 
5225  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
5227  BM_face_select_set(em->bm, f, true);
5228  }
5229  }
5230 
5232 
5235  }
5236  MEM_freeN(objects);
5237 
5238  return OPERATOR_FINISHED;
5239 }
5240 
5242 {
5243  /* identifiers */
5244  ot->name = "Select Loop Inner-Region";
5245  ot->idname = "MESH_OT_loop_to_region";
5246  ot->description = "Select region of faces inside of a selected loop of edges";
5247 
5248  /* api callbacks */
5251 
5252  /* flags */
5254 
5256  "select_bigger",
5257  0,
5258  "Select Bigger",
5259  "Select bigger regions instead of smaller ones");
5260 }
5261 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1006
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1208
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
bool CustomData_has_layer(const struct CustomData *data, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:423
#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:420
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:394
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:430
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_pop(arr)
Definition: BLI_array.h:125
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_array_free(arr)
Definition: BLI_array.h:116
#define BLI_assert(a)
Definition: BLI_assert.h:58
struct GSet GSet
Definition: BLI_ghash.h:189
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
void BLI_gset_insert(GSet *gs, void *key)
Definition: BLI_ghash.c:1147
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1216
GSet * BLI_gset_ptr_new_ex(const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:1160
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition: BLI_heap.c:221
Heap * BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT
Definition: BLI_heap.c:201
void void float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:399
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:305
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:338
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
Definition: BLI_heap.c:268
void * BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:404
HeapNode * BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:319
void void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:257
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
int BLI_listbase_count_at_most(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE float min_ff(float a, float b)
MINLINE unsigned short highest_order_bit_s(unsigned short n)
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:3469
float dist_squared_ray_to_seg_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], float r_point[3], float *r_depth)
Definition: math_geom.c:622
float dist_squared_to_ray_v3_normalized(const float ray_origin[3], const float ray_direction[3], const float co[3])
Definition: math_geom.c:600
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
bool invert_m3(float R[3][3])
Definition: math_matrix.c:1152
#define DEG2RADF(_deg)
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t)
Definition: math_vector.c:32
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void mid_v2_v2v2(float r[2], const float a[2], const float b[2])
Definition: math_vector.c:277
MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:505
Random number functions.
void BLI_array_randomize(void *data, unsigned int elem_size, unsigned int elem_tot, unsigned int seed)
Definition: rand.cc:208
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNPACK2(a)
#define UNUSED_VARS(...)
#define SWAP(type, a, b)
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define STACK_CLEAR(stack)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_INIT(stack, tot)
#define STACK_SIZE(stack)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
struct ID * DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
@ CD_FACEMAP
@ CD_MDEFORMVERT
@ CD_MLOOPUV
@ ME_EDIT_MIRROR_TOPO
Object is a sort of wrapper for general info.
@ OB_MESH
#define SCE_SELECT_FACE
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ V3D_ORIENT_LOCAL
@ V3D_AROUND_ACTIVE
#define RV3D_CLIPPING
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
bool DRW_select_buffer_elem_get(const uint sel_id, uint *r_elem, uint *r_base_index, char *r_elem_type)
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int center[2], const uint id_min, const uint id_max, uint *dist)
void DRW_select_buffer_context_create(struct Base **bases, const uint bases_len, short select_mode)
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int center[2])
void EDBM_selectmode_to_scene(struct bContext *C)
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode)
void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step)
struct BMFace * EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *f)
void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag)
void EDBM_select_flush(struct BMEditMesh *em)
void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step)
struct BMVert * EDBM_verts_mirror_get(struct BMEditMesh *em, struct BMVert *v)
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em)
void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
void EDBM_deselect_flush(struct BMEditMesh *em)
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em, const int axis, const bool use_self, const bool use_select, const bool respecthide, const bool use_topology)
void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode)
Definition: mesh_data.c:1332
struct BMEdge * EDBM_verts_mirror_get_edge(struct BMEditMesh *em, struct BMEdge *e)
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag)
void EDBM_selectmode_flush(struct BMEditMesh *em)
void ED_object_base_activate(struct bContext *C, struct Base *base)
bool ED_operator_editmesh_region_view3d(struct bContext *C)
Definition: screen_ops.c:418
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:404
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
short ED_transform_calc_orientation_from_type_ex(const struct bContext *C, float r_mat[3][3], struct Scene *scene, struct RegionView3D *rv3d, struct Object *ob, struct Object *obedit, const short orientation_index, const int pivot_point)
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:190
eV3DProjTest
Definition: ED_view3d.h:192
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:196
@ V3D_PROJ_TEST_CLIP_BB
Definition: ED_view3d.h:194
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], const eV3DProjTest flag)
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact)
void mesh_foreachScreenFace(struct ViewContext *vc, void(*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index), void *userData, const eV3DProjTest clip_flag)
void mesh_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index), void *userData, const eV3DProjTest clip_flag)
#define V3D_PROJ_TEST_CLIP_DEFAULT
Definition: ED_view3d.h:201
#define XRAY_FLAG_ENABLED(v3d)
Definition: ED_view3d.h:709
void view3d_operator_needs_opengl(const struct bContext *C)
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local)
float ED_view3d_select_dist_px(void)
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3], const bool do_clip)
void mesh_foreachScreenEdge(struct ViewContext *vc, void(*func)(void *userData, struct BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index), void *userData, const eV3DProjTest clip_flag)
int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist)
Definition: view3d_draw.c:2201
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define NC_SCENE
Definition: WM_types.h:279
#define ND_TOOLSETTINGS
Definition: WM_types.h:349
#define NC_MATERIAL
Definition: WM_types.h:281
#define ND_SELECT
Definition: WM_types.h:407
#define ND_SHADING_LINKS
Definition: WM_types.h:379
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_LOOPS_OF_LOOP
@ BM_FACES_OF_EDGE
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_mesh_deselect_flush(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMVert * BM_mesh_active_vert_get(BMesh *bm)
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
BMElem * BM_mesh_active_elem_get(BMesh *bm)
#define BM_select_history_store(bm, ele)
#define BM_select_history_remove(bm, ele)
void BM_mesh_elem_toolflags_clear(BMesh *bm)
Definition: bmesh_mesh.c:132
BMEdge * BM_edge_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2425
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
Definition: bmesh_mesh.c:98
BMFace * BM_face_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2433
BMVert * BM_vert_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2417
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:110
#define BMO_edge_flag_test(bm, e, oflag)
void BMO_pop(BMesh *bm)
BMESH OPSTACK POP.
#define BMO_edge_flag_set(bm, e, oflag, val)
void BMO_push(BMesh *bm, BMOperator *op)
#define BMO_elem_flag_enable(bm, ele, oflag)
@ BMO_DELIM_NORMAL
@ BMO_DELIM_MATERIAL
@ BMO_DELIM_SEAM
@ BMO_DELIM_SHARP
@ BMO_DELIM_UV
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_center_median_vcos(const BMesh *bm, const BMFace *f, float r_cent[3], float const (*vertexCos)[3])
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e, const int cd_loop_type, const int cd_loop_offset)
Definition: bmesh_query.c:1127
bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide)
Definition: bmesh_query.c:2446
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMLoopFilterFunc filter_fn, BMLoopPairFilterFunc filter_pair_fn, void *user_data, const char hflag_test, const char htype_step)
Definition: bmesh_query.c:2611
bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag)
Definition: bmesh_query.c:2500
bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag)
Definition: bmesh_query.c:2486
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
Definition: bmesh_query.c:753
bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
Definition: bmesh_query.c:2410
bool BM_vert_is_manifold(const BMVert *v)
Definition: bmesh_query.c:943
int BM_edge_face_count(const BMEdge *e)
Definition: bmesh_query.c:847
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
Definition: bmesh_query.c:2481
float BM_edge_calc_length(const BMEdge *e)
Definition: bmesh_query.c:713
bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
Definition: bmesh_query.c:2428
bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
Definition: bmesh_query.c:2464
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_edge_face_count_is_over(e, n)
Definition: bmesh_query.h:97
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
int BM_mesh_region_match(BMesh *bm, BMFace **faces_region, uint faces_region_len, ListBase *r_face_regions)
void BMW_init(BMWalker *walker, BMesh *bm, int type, short mask_vert, short mask_edge, short mask_face, BMWFlag flag, int layer)
Init Walker.
Definition: bmesh_walkers.c:70
void BMW_end(BMWalker *walker)
End Walker.
int BMW_current_depth(BMWalker *walker)
Walker Current Depth.
void * BMW_begin(BMWalker *walker, void *start)
Definition: bmesh_walkers.c:55
void * BMW_step(BMWalker *walker)
Step Walker.
@ BMW_BREADTH_FIRST
Definition: bmesh_walkers.h:29
#define BMW_NIL_LAY
@ BMW_FLAG_NOP
Definition: bmesh_walkers.h:33
@ BMW_FLAG_TEST_HIDDEN
Definition: bmesh_walkers.h:34
#define BMW_MASK_NOP
Definition: bmesh_walkers.h:68
@ BMW_EDGERING
@ BMW_CONNECTED_VERTEX
@ BMW_FACELOOP
@ BMW_EDGELOOP
@ BMW_FACE_SHELL
@ BMW_EDGELOOP_NONMANIFOLD
@ BMW_VERT_SHELL
@ BMW_LOOP_SHELL_WIRE
@ BMW_ISLAND
@ BMW_EDGEBOUNDARY
#define BMW_ITER(ele, walker, data)
Definition: bmesh_walkers.h:90
static unsigned long seed
Definition: btSoftBody.h:39
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
Scene scene
const Depsgraph * depsgraph
void * user_data
static int edbm_select_all_exec(bContext *C, wmOperator *op)
static void walker_select_count(BMEditMesh *em, int walkercode, void *start, int r_count_by_select[2])
void MESH_OT_select_less(wmOperatorType *ot)
bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
static int edbm_select_random_exec(bContext *C, wmOperator *op)
static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_lengths)
static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
void em_setup_viewcontext(bContext *C, ViewContext *vc)
void MESH_OT_loop_to_region(wmOperatorType *ot)
void MESH_OT_select_mode(wmOperatorType *ot)
void EDBM_select_toggle_all(BMEditMesh *em)
static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void select_linked_delimit_end(BMEditMesh *em)
void MESH_OT_select_similar_region(wmOperatorType *ot)
#define FIND_NEAR_SELECT_BIAS
static int edbm_select_mode_exec(bContext *C, wmOperator *op)
static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
void MESH_OT_select_linked_pick(wmOperatorType *ot)
static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op)
static int edbm_select_more_exec(bContext *C, wmOperator *op)
static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ***region_out)
BMFace * EDBM_face_find_nearest_ex(ViewContext *vc, float *dist_px_manhattan_p, float *r_dist_center, const bool use_zbuf_single_px, const bool use_select_bias, bool use_cycle, BMFace **r_efa_zbuf, Base **bases, uint bases_len, uint *r_base_index)
@ SELECT_AXIS_ALIGN
@ SELECT_AXIS_POS
@ SELECT_AXIS_NEG
void EDBM_select_swap(BMEditMesh *em)
static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
static int edbm_loop_to_region_exec(bContext *C, wmOperator *op)
static void mouse_mesh_loop_edge_ring(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
void EDBM_selectmode_set(BMEditMesh *em)
static BMElem * edbm_select_id_bm_elem_get(Base **bases, const uint sel_id, uint *r_base_index)
static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
static void walker_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params, BMHeader *h_act)
void MESH_OT_select_random(wmOperatorType *ot)
bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, Base **bases, const uint bases_len, bool use_boundary_vertices, bool use_boundary_edges, int *r_base_index_vert, int *r_base_index_edge, int *r_base_index_face, struct BMVert **r_eve, struct BMEdge **r_eed, struct BMFace **r_efa)
static bool unified_findnearest(ViewContext *vc, Base **bases, const uint bases_len, int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
static int verg_radial(const void *va, const void *vb)
static int loop_find_regions(BMEditMesh *em, const bool selbigger)
void MESH_OT_select_nth(wmOperatorType *ot)
bool EDBM_selectmode_disable_multi(struct bContext *C, const short selectmode_disable, const short selectmode_fallback)
static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
static int edbm_select_loose_exec(bContext *C, wmOperator *op)
static void find_nearest_face_center__doZBuf(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
void MESH_OT_loop_multi_select(wmOperatorType *ot)
#define BMO_ELE_TAG
BMFace * EDBM_face_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new)
bool EDBM_selectmode_disable_multi_ex(Scene *scene, struct Base **bases, const uint bases_len, const short selectmode_disable, const short selectmode_fallback)
static void select_linked_delimit_validate(BMesh *bm, int *delimit)
static bool select_linked_delimit_test(BMEdge *e, int delimit, const struct DelimitData *delimit_data)
static int edbm_select_less_exec(bContext *C, wmOperator *op)
bool EDBM_selectmode_toggle_multi(bContext *C, const short selectmode_new, const int action, const bool use_extend, const bool use_expand)
static bool bm_interior_loop_filter_fn(const BMLoop *l, void *UNUSED(user_data))
static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op)
static int edbm_select_axis_exec(bContext *C, wmOperator *op)
void EDBM_select_mirrored(BMEditMesh *em, const Mesh *me, const int axis, const bool extend, int *r_totmirr, int *r_totfail)
void MESH_OT_select_loose(wmOperatorType *ot)
bool EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select)
BMEdge * EDBM_edge_find_nearest_ex(ViewContext *vc, float *dist_px_manhattan_p, float *r_dist_center_px_manhattan, const bool use_select_bias, bool use_cycle, BMEdge **r_eed_zbuf, Base **bases, uint bases_len, uint *r_base_index)
void MESH_OT_edgering_select(wmOperatorType *ot)
static bool edbm_select_ungrouped_poll(bContext *C)
static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
void MESH_OT_select_face_by_sides(wmOperatorType *ot)
BMEdge * EDBM_edge_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
void MESH_OT_select_axis(wmOperatorType *ot)
static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params)
static void walker_select(BMEditMesh *em, int walkercode, void *start, const bool select)
void MESH_OT_select_mirror(wmOperatorType *ot)
static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
void MESH_OT_edges_select_sharp(wmOperatorType *ot)
static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle)
static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode)
static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
BMVert * EDBM_vert_find_nearest_ex(ViewContext *vc, float *dist_px_manhattan_p, const bool use_select_bias, bool use_cycle, Base **bases, uint bases_len, uint *r_base_index)
static void find_nearest_edge__doClosest(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
static bool bm_edge_is_select_isolated(BMEdge *e)
void MESH_OT_select_interior_faces(wmOperatorType *ot)
static void find_nearest_edge_center__doZBuf(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
void MESH_OT_select_linked(wmOperatorType *ot)
static void select_linked_delimit_begin(BMesh *bm, int delimit)
static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool EDBM_mesh_deselect_all_multi(struct bContext *C)
static bool bm_interior_edge_is_manifold_except_face_index(BMEdge *e, int face_index, BMLoop *r_l_pair[2])
static int edbm_select_linked_exec(bContext *C, wmOperator *op)
void MESH_OT_select_all(wmOperatorType *ot)
BMVert * EDBM_vert_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
void MESH_OT_select_more(wmOperatorType *ot)
static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
#define FIND_NEAR_CYCLE_THRESHOLD_MIN
bool EDBM_select_interior_faces(BMEditMesh *em)
void MESH_OT_region_to_loop(wmOperatorType *ot)
static void edbm_strip_selections(BMEditMesh *em)
void MESH_OT_loop_select(wmOperatorType *ot)
static int edbm_select_nth_exec(bContext *C, wmOperator *op)
bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
bool EDBM_unified_findnearest(ViewContext *vc, Base **bases, const uint bases_len, int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
void MESH_OT_select_ungrouped(wmOperatorType *ot)
bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em, const short selectmode_disable, const short selectmode_fallback)
void MESH_OT_select_non_manifold(wmOperatorType *ot)
BMElem * EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
BMElem * EDBM_elem_from_index_any_multi(ViewLayer *view_layer, int object_index, int elem_index, Object **r_obedit)
int EDBM_elem_to_index_any_multi(ViewLayer *view_layer, BMEditMesh *em, BMElem *ele, int *r_object_index)
#define UINT_MAX
Definition: hash_md5.c:58
int count
#define cosf(x)
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static char faces[256]
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
double sign(double arg)
Definition: utility.h:250
static void area(int d1, int d2, int e1, int e2, float weights[2])
return ret
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3562
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3543
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_enum_flag(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3795
void RNA_def_property_float_default(PropertyRNA *prop, float value)
Definition: rna_define.c:2042
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
PropertyRNA * RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:4005
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]
Definition: rna_mesh.c:49
const EnumPropertyItem rna_enum_axis_flag_xyz_items[]
Definition: rna_modifier.c:591
const EnumPropertyItem rna_enum_axis_xyz_items[]
Definition: rna_modifier.c:584
const EnumPropertyItem rna_enum_mesh_select_mode_items[]
Definition: rna_scene.c:143
const EnumPropertyItem rna_enum_transform_orientation_items[]
Definition: rna_scene.c:578
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
short selectmode
Definition: BKE_editmesh.h:72
struct BMesh * bm
Definition: BKE_editmesh.h:52
short mat_nr
Definition: BKE_editmesh.h:73
struct BMEditSelection * next
Definition: bmesh_marking.h:24
BMHeader head
Definition: bmesh_class.h:255
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:279
BMHeader head
Definition: bmesh_class.h:267
float no[3]
Definition: bmesh_class.h:280
char htype
Definition: bmesh_class.h:76
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
BMHeader head
Definition: bmesh_class.h:97
BMWOrder order
Definition: bmesh_walkers.h:44
int totvert
Definition: bmesh_class.h:297
int totfacesel
Definition: bmesh_class.h:298
char elem_index_dirty
Definition: bmesh_class.h:305
CustomData vdata
Definition: bmesh_class.h:337
int totedge
Definition: bmesh_class.h:297
ListBase selected
Definition: bmesh_class.h:356
int totvertsel
Definition: bmesh_class.h:298
short selectmode
Definition: bmesh_class.h:350
int totedgesel
Definition: bmesh_class.h:298
CustomData pdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
struct Object * object
const float(* vertexCos)[3]
Definition: BLI_heap.c:57
char name[66]
Definition: DNA_ID.h:283
void * data
Definition: DNA_listBase.h:42
void * first
Definition: DNA_listBase.h:47
struct MDeformWeight * dw
struct EditMeshData * edit_data
char editflag
Mesh_Runtime runtime
struct NearestEdgeUserData_Hit hit
struct NearestEdgeUserData_Hit hit_cycle
struct NearestFaceUserData_Hit hit
struct NearestFaceUserData_Hit hit_cycle
struct NearestVertUserData_Hit hit
struct NearestVertUserData_Hit hit_cycle
ListBase defbase
unsigned short actfmap
float obmat[4][4]
void * data
ListBase fmaps
struct ToolSettings * toolsettings
struct Depsgraph * depsgraph
Definition: ED_view3d.h:75
int mval[2]
Definition: ED_view3d.h:85
struct Scene * scene
Definition: ED_view3d.h:76
struct ARegion * region
Definition: ED_view3d.h:80
struct ViewLayer * view_layer
Definition: ED_view3d.h:77
struct BMEditMesh * em
Definition: ED_view3d.h:84
struct Object * obact
Definition: ED_view3d.h:78
struct Object * obedit
Definition: ED_view3d.h:79
struct View3D * v3d
Definition: ED_view3d.h:81
struct RegionView3D * rv3d
Definition: ED_view3d.h:83
struct Base * basact
short shift
Definition: WM_types.h:618
short ctrl
Definition: WM_types.h:618
int mval[2]
Definition: WM_types.h:583
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct PointerRNA * ptr
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op)
bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalParams *op_params, int depth)
void WM_operator_properties_select_random(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op, struct CheckerIntervalParams *op_params)
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)