Blender  V3.3
editmesh_select.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_array.h"
11 #include "BLI_bitmap.h"
12 #include "BLI_heap.h"
13 #include "BLI_linklist.h"
14 #include "BLI_linklist_stack.h"
15 #include "BLI_listbase.h"
16 #include "BLI_math.h"
17 #include "BLI_math_bits.h"
18 #include "BLI_rand.h"
19 #include "BLI_string.h"
20 #include "BLI_utildefines_stack.h"
21 
22 #include "BKE_context.h"
23 #include "BKE_customdata.h"
24 #include "BKE_deform.h"
25 #include "BKE_editmesh.h"
26 #include "BKE_layer.h"
27 #include "BKE_report.h"
28 
29 #include "WM_api.h"
30 #include "WM_types.h"
31 
32 #include "RNA_access.h"
33 #include "RNA_define.h"
34 #include "RNA_enum_types.h"
35 
36 #include "ED_mesh.h"
37 #include "ED_object.h"
38 #include "ED_screen.h"
39 #include "ED_select_utils.h"
40 #include "ED_transform.h"
41 #include "ED_view3d.h"
42 
43 #include "BLT_translation.h"
44 
45 #include "DNA_mesh_types.h"
46 #include "DNA_meshdata_types.h"
47 #include "DNA_object_types.h"
48 
49 #include "UI_resources.h"
50 
51 #include "bmesh_tools.h"
52 
53 #include "DEG_depsgraph.h"
54 #include "DEG_depsgraph_query.h"
55 
56 #include "DRW_select_buffer.h"
57 
58 #include "mesh_intern.h" /* own include */
59 
60 /* use bmesh operator flags for a few operators */
61 #define BMO_ELE_TAG 1
62 
63 /* -------------------------------------------------------------------- */
68  const Mesh *me,
69  const int axis,
70  const bool extend,
71  int *r_totmirr,
72  int *r_totfail)
73 {
74  BMesh *bm = em->bm;
75  BMIter iter;
76  int totmirr = 0;
77  int totfail = 0;
78  bool use_topology = me->editflag & ME_EDIT_MIRROR_TOPO;
79 
80  *r_totmirr = *r_totfail = 0;
81 
82  /* select -> tag */
84  BMVert *v;
85  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
87  }
88  }
89  else if (em->selectmode & SCE_SELECT_EDGE) {
90  BMEdge *e;
91  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
93  }
94  }
95  else {
96  BMFace *f;
97  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
99  }
100  }
101 
102  EDBM_verts_mirror_cache_begin(em, axis, true, true, false, use_topology);
103 
104  if (!extend) {
106  }
107 
109  BMVert *v;
110  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
112  BMVert *v_mirr = EDBM_verts_mirror_get(em, v);
113  if (v_mirr && !BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) {
114  BM_vert_select_set(bm, v_mirr, true);
115  totmirr++;
116  }
117  else {
118  totfail++;
119  }
120  }
121  }
122  }
123  else if (em->selectmode & SCE_SELECT_EDGE) {
124  BMEdge *e;
125  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
127  BMEdge *e_mirr = EDBM_verts_mirror_get_edge(em, e);
128  if (e_mirr && !BM_elem_flag_test(e_mirr, BM_ELEM_HIDDEN)) {
129  BM_edge_select_set(bm, e_mirr, true);
130  totmirr++;
131  }
132  else {
133  totfail++;
134  }
135  }
136  }
137  }
138  else {
139  BMFace *f;
140  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
142  BMFace *f_mirr = EDBM_verts_mirror_get_face(em, f);
143  if (f_mirr && !BM_elem_flag_test(f_mirr, BM_ELEM_HIDDEN)) {
144  BM_face_select_set(bm, f_mirr, true);
145  totmirr++;
146  }
147  else {
148  totfail++;
149  }
150  }
151  }
152  }
153 
155 
156  *r_totmirr = totmirr;
157  *r_totfail = totfail;
158 }
159 
162 /* -------------------------------------------------------------------- */
166 static BMElem *edbm_select_id_bm_elem_get(Base **bases, const uint sel_id, uint *r_base_index)
167 {
168  uint elem_id;
169  char elem_type = 0;
170  bool success = DRW_select_buffer_elem_get(sel_id, &elem_id, r_base_index, &elem_type);
171 
172  if (success) {
173  Object *obedit = bases[*r_base_index]->object;
174  BMEditMesh *em = BKE_editmesh_from_object(obedit);
175 
176  switch (elem_type) {
177  case SCE_SELECT_FACE:
178  return (BMElem *)BM_face_at_index_find_or_table(em->bm, elem_id);
179  case SCE_SELECT_EDGE:
180  return (BMElem *)BM_edge_at_index_find_or_table(em->bm, elem_id);
181  case SCE_SELECT_VERTEX:
182  return (BMElem *)BM_vert_at_index_find_or_table(em->bm, elem_id);
183  default:
184  BLI_assert(0);
185  return NULL;
186  }
187  }
188 
189  return NULL;
190 }
191 
194 /* -------------------------------------------------------------------- */
205 #define FIND_NEAR_SELECT_BIAS 5
206 #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
207 
209  float dist;
210  float dist_bias;
211  int index;
213 };
214 
216  float mval_fl[2];
218  bool use_cycle;
220 
223 };
224 
225 static void findnearestvert__doClosest(void *userData,
226  BMVert *eve,
227  const float screen_co[2],
228  int index)
229 {
230  struct NearestVertUserData *data = userData;
231  float dist_test, dist_test_bias;
232 
233  dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
234 
235  if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
236  dist_test_bias += FIND_NEAR_SELECT_BIAS;
237  }
238 
239  if (dist_test_bias < data->hit.dist_bias) {
240  data->hit.dist_bias = dist_test_bias;
241  data->hit.dist = dist_test;
242  data->hit.index = index;
243  data->hit.vert = eve;
244  }
245 
246  if (data->use_cycle) {
247  if ((data->hit_cycle.vert == NULL) && (index > data->cycle_index_prev) &&
248  (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) {
249  data->hit_cycle.dist_bias = dist_test_bias;
250  data->hit_cycle.dist = dist_test;
251  data->hit_cycle.index = index;
252  data->hit_cycle.vert = eve;
253  }
254  }
255 }
256 
258  float *dist_px_manhattan_p,
259  const bool use_select_bias,
260  bool use_cycle,
261  Base **bases,
262  uint bases_len,
263  uint *r_base_index)
264 {
265  uint base_index = 0;
266 
267  if (!XRAY_FLAG_ENABLED(vc->v3d)) {
268  uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region,
269  *dist_px_manhattan_p);
270  uint index;
271  BMVert *eve;
272 
273  /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
274  {
276 
278  vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
279 
280  if (index) {
281  eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index);
282  }
283  else {
284  eve = NULL;
285  }
286  }
287 
288  if (eve) {
289  if (dist_px_manhattan_test < *dist_px_manhattan_p) {
290  if (r_base_index) {
291  *r_base_index = base_index;
292  }
293  *dist_px_manhattan_p = dist_px_manhattan_test;
294  return eve;
295  }
296  }
297  return NULL;
298  }
299 
300  struct NearestVertUserData data = {{0}};
301  const struct NearestVertUserData_Hit *hit = NULL;
302  const eV3DProjTest clip_flag = RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d) ?
305  BMesh *prev_select_bm = NULL;
306 
307  static struct {
308  int index;
309  const BMVert *elem;
310  const BMesh *bm;
311  } prev_select = {0};
312 
313  data.mval_fl[0] = vc->mval[0];
314  data.mval_fl[1] = vc->mval[1];
315  data.use_select_bias = use_select_bias;
316  data.use_cycle = use_cycle;
317 
318  for (; base_index < bases_len; base_index++) {
319  Base *base_iter = bases[base_index];
321  if (use_cycle && prev_select.bm == vc->em->bm &&
322  prev_select.elem == BM_vert_at_index_find_or_table(vc->em->bm, prev_select.index)) {
323  data.cycle_index_prev = prev_select.index;
324  /* No need to compare in the rest of the loop. */
325  use_cycle = false;
326  }
327  else {
328  data.cycle_index_prev = 0;
329  }
330 
331  data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias =
332  *dist_px_manhattan_p;
333 
336 
337  hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit;
338 
339  if (hit->dist < *dist_px_manhattan_p) {
340  if (r_base_index) {
341  *r_base_index = base_index;
342  }
343  *dist_px_manhattan_p = hit->dist;
344  prev_select_bm = vc->em->bm;
345  }
346  }
347 
348  if (hit == NULL) {
349  return NULL;
350  }
351 
352  prev_select.index = hit->index;
353  prev_select.elem = hit->vert;
354  prev_select.bm = prev_select_bm;
355 
356  return hit->vert;
357 }
358 
359 BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
360 {
361  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
362  return EDBM_vert_find_nearest_ex(vc, dist_px_manhattan_p, false, false, &base, 1, NULL);
363 }
364 
365 /* find the distance to the edge we already have */
367  float mval_fl[2];
368  float dist;
370 };
371 
372 static void find_nearest_edge_center__doZBuf(void *userData,
373  BMEdge *eed,
374  const float screen_co_a[2],
375  const float screen_co_b[2],
376  int UNUSED(index))
377 {
378  struct NearestEdgeUserData_ZBuf *data = userData;
379 
380  if (eed == data->edge_test) {
381  float dist_test;
382  float screen_co_mid[2];
383 
384  mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
385  dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
386 
387  if (dist_test < data->dist) {
388  data->dist = dist_test;
389  }
390  }
391 }
392 
394  float dist;
395  float dist_bias;
396  int index;
398 
399  /* edges only, un-biased manhattan distance to which ever edge we pick
400  * (not used for choosing) */
402 };
403 
406  float mval_fl[2];
408  bool use_cycle;
410 
413 };
414 
415 /* NOTE: uses v3d, so needs active 3d window. */
417  void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
418 {
419  struct NearestEdgeUserData *data = userData;
420  float dist_test, dist_test_bias;
421 
422  float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
423  float screen_co[2];
424 
425  if (fac <= 0.0f) {
426  fac = 0.0f;
427  copy_v2_v2(screen_co, screen_co_a);
428  }
429  else if (fac >= 1.0f) {
430  fac = 1.0f;
431  copy_v2_v2(screen_co, screen_co_b);
432  }
433  else {
434  interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac);
435  }
436 
437  dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
438 
439  if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
440  dist_test_bias += FIND_NEAR_SELECT_BIAS;
441  }
442 
443  if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
444  float vec[3];
445 
446  interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac);
447  if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) {
448  return;
449  }
450  }
451 
452  if (dist_test_bias < data->hit.dist_bias) {
453  float screen_co_mid[2];
454 
455  data->hit.dist_bias = dist_test_bias;
456  data->hit.dist = dist_test;
457  data->hit.index = index;
458  data->hit.edge = eed;
459 
460  mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
461  data->hit.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
462  }
463 
464  if (data->use_cycle) {
465  if ((data->hit_cycle.edge == NULL) && (index > data->cycle_index_prev) &&
466  (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) {
467  float screen_co_mid[2];
468 
469  data->hit_cycle.dist_bias = dist_test_bias;
470  data->hit_cycle.dist = dist_test;
471  data->hit_cycle.index = index;
472  data->hit_cycle.edge = eed;
473 
474  mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
475  data->hit_cycle.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
476  }
477  }
478 }
479 
481  float *dist_px_manhattan_p,
482  float *r_dist_center_px_manhattan,
483  const bool use_select_bias,
484  bool use_cycle,
485  BMEdge **r_eed_zbuf,
486  Base **bases,
487  uint bases_len,
488  uint *r_base_index)
489 {
490  uint base_index = 0;
491 
492  if (!XRAY_FLAG_ENABLED(vc->v3d)) {
493  uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region,
494  *dist_px_manhattan_p);
495  uint index;
496  BMEdge *eed;
497 
498  /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
499  {
501 
503  vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
504 
505  if (index) {
506  eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index);
507  }
508  else {
509  eed = NULL;
510  }
511  }
512 
513  if (r_eed_zbuf) {
514  *r_eed_zbuf = eed;
515  }
516 
517  /* exception for faces (verts don't need this) */
518  if (r_dist_center_px_manhattan && eed) {
520 
521  data.mval_fl[0] = vc->mval[0];
522  data.mval_fl[1] = vc->mval[1];
523  data.dist = FLT_MAX;
524  data.edge_test = eed;
525 
527 
530  &data,
532 
533  *r_dist_center_px_manhattan = data.dist;
534  }
535  /* end exception */
536 
537  if (eed) {
538  if (dist_px_manhattan_test < *dist_px_manhattan_p) {
539  if (r_base_index) {
540  *r_base_index = base_index;
541  }
542  *dist_px_manhattan_p = dist_px_manhattan_test;
543  return eed;
544  }
545  }
546  return NULL;
547  }
548 
549  struct NearestEdgeUserData data = {{0}};
550  const struct NearestEdgeUserData_Hit *hit = NULL;
551  /* interpolate along the edge before doing a clipping plane test */
553  BMesh *prev_select_bm = NULL;
554 
555  static struct {
556  int index;
557  const BMEdge *elem;
558  const BMesh *bm;
559  } prev_select = {0};
560 
561  data.vc = *vc;
562  data.mval_fl[0] = vc->mval[0];
563  data.mval_fl[1] = vc->mval[1];
564  data.use_select_bias = use_select_bias;
565  data.use_cycle = use_cycle;
566 
567  for (; base_index < bases_len; base_index++) {
568  Base *base_iter = bases[base_index];
570  if (use_cycle && prev_select.bm == vc->em->bm &&
571  prev_select.elem == BM_edge_at_index_find_or_table(vc->em->bm, prev_select.index)) {
572  data.cycle_index_prev = prev_select.index;
573  /* No need to compare in the rest of the loop. */
574  use_cycle = false;
575  }
576  else {
577  data.cycle_index_prev = 0;
578  }
579 
580  data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias =
581  *dist_px_manhattan_p;
582 
586 
587  hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
588 
589  if (hit->dist < *dist_px_manhattan_p) {
590  if (r_base_index) {
591  *r_base_index = base_index;
592  }
593  *dist_px_manhattan_p = hit->dist;
594  prev_select_bm = vc->em->bm;
595  }
596  }
597 
598  if (hit == NULL) {
599  return NULL;
600  }
601 
602  if (r_dist_center_px_manhattan) {
603  *r_dist_center_px_manhattan = hit->dist_center_px_manhattan;
604  }
605 
606  prev_select.index = hit->index;
607  prev_select.elem = hit->edge;
608  prev_select.bm = prev_select_bm;
609 
610  return hit->edge;
611 }
612 
613 BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
614 {
615  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
617  vc, dist_px_manhattan_p, NULL, false, false, NULL, &base, 1, NULL);
618 }
619 
620 /* find the distance to the face we already have */
622  float mval_fl[2];
625 };
626 
627 static void find_nearest_face_center__doZBuf(void *userData,
628  BMFace *efa,
629  const float screen_co[2],
630  int UNUSED(index))
631 {
632  struct NearestFaceUserData_ZBuf *data = userData;
633 
634  if (efa == data->face_test) {
635  const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
636 
637  if (dist_test < data->dist_px_manhattan) {
638  data->dist_px_manhattan = dist_test;
639  }
640  }
641 }
642 
644  float dist;
645  float dist_bias;
646  int index;
648 };
649 
651  float mval_fl[2];
653  bool use_cycle;
655 
658 };
659 
660 static void findnearestface__doClosest(void *userData,
661  BMFace *efa,
662  const float screen_co[2],
663  int index)
664 {
665  struct NearestFaceUserData *data = userData;
666  float dist_test, dist_test_bias;
667 
668  dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
669 
670  if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
671  dist_test_bias += FIND_NEAR_SELECT_BIAS;
672  }
673 
674  if (dist_test_bias < data->hit.dist_bias) {
675  data->hit.dist_bias = dist_test_bias;
676  data->hit.dist = dist_test;
677  data->hit.index = index;
678  data->hit.face = efa;
679  }
680 
681  if (data->use_cycle) {
682  if ((data->hit_cycle.face == NULL) && (index > data->cycle_index_prev) &&
683  (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) {
684  data->hit_cycle.dist_bias = dist_test_bias;
685  data->hit_cycle.dist = dist_test;
686  data->hit_cycle.index = index;
687  data->hit_cycle.face = efa;
688  }
689  }
690 }
691 
693  float *dist_px_manhattan_p,
694  float *r_dist_center,
695  const bool use_zbuf_single_px,
696  const bool use_select_bias,
697  bool use_cycle,
698  BMFace **r_efa_zbuf,
699  Base **bases,
700  uint bases_len,
701  uint *r_base_index)
702 {
703  uint base_index = 0;
704 
705  if (!XRAY_FLAG_ENABLED(vc->v3d)) {
706  float dist_test;
707  uint index;
708  BMFace *efa;
709 
710  {
711  uint dist_px_manhattan_test = 0;
712  if (*dist_px_manhattan_p != 0.0f && (use_zbuf_single_px == false)) {
713  dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region,
714  *dist_px_manhattan_p);
715  }
716 
718 
719  if (dist_px_manhattan_test == 0) {
720  index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, vc->mval);
721  dist_test = 0.0f;
722  }
723  else {
725  vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
726  dist_test = dist_px_manhattan_test;
727  }
728 
729  if (index) {
730  efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index);
731  }
732  else {
733  efa = NULL;
734  }
735  }
736 
737  if (r_efa_zbuf) {
738  *r_efa_zbuf = efa;
739  }
740 
741  /* exception for faces (verts don't need this) */
742  if (r_dist_center && efa) {
744 
745  data.mval_fl[0] = vc->mval[0];
746  data.mval_fl[1] = vc->mval[1];
747  data.dist_px_manhattan = FLT_MAX;
748  data.face_test = efa;
749 
751 
754 
755  *r_dist_center = data.dist_px_manhattan;
756  }
757  /* end exception */
758 
759  if (efa) {
760  if (dist_test < *dist_px_manhattan_p) {
761  if (r_base_index) {
762  *r_base_index = base_index;
763  }
764  *dist_px_manhattan_p = dist_test;
765  return efa;
766  }
767  }
768  return NULL;
769  }
770 
771  struct NearestFaceUserData data = {{0}};
772  const struct NearestFaceUserData_Hit *hit = NULL;
773  const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
774  BMesh *prev_select_bm = NULL;
775 
776  static struct {
777  int index;
778  const BMFace *elem;
779  const BMesh *bm;
780  } prev_select = {0};
781 
782  data.mval_fl[0] = vc->mval[0];
783  data.mval_fl[1] = vc->mval[1];
784  data.use_select_bias = use_select_bias;
785  data.use_cycle = use_cycle;
786 
787  for (; base_index < bases_len; base_index++) {
788  Base *base_iter = bases[base_index];
790  if (use_cycle && prev_select.bm == vc->em->bm &&
791  prev_select.elem == BM_face_at_index_find_or_table(vc->em->bm, prev_select.index)) {
792  data.cycle_index_prev = prev_select.index;
793  /* No need to compare in the rest of the loop. */
794  use_cycle = false;
795  }
796  else {
797  data.cycle_index_prev = 0;
798  }
799 
800  data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias =
801  *dist_px_manhattan_p;
802 
805 
806  hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
807 
808  if (hit->dist < *dist_px_manhattan_p) {
809  if (r_base_index) {
810  *r_base_index = base_index;
811  }
812  *dist_px_manhattan_p = hit->dist;
813  prev_select_bm = vc->em->bm;
814  }
815  }
816 
817  if (hit == NULL) {
818  return NULL;
819  }
820 
821  if (r_dist_center) {
822  *r_dist_center = hit->dist;
823  }
824 
825  prev_select.index = hit->index;
826  prev_select.elem = hit->face;
827  prev_select.bm = prev_select_bm;
828 
829  return hit->face;
830 }
831 
832 BMFace *EDBM_face_find_nearest(ViewContext *vc, float *dist_px_manhattan_p)
833 {
834  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
836  vc, dist_px_manhattan_p, NULL, false, false, false, NULL, &base, 1, NULL);
837 }
838 
839 #undef FIND_NEAR_SELECT_BIAS
840 #undef FIND_NEAR_CYCLE_THRESHOLD_MIN
841 
842 /* best distance based on screen coords.
843  * use em->selectmode to define how to use
844  * selected vertices and edges get disadvantage
845  * return 1 if found one
846  */
848  Base **bases,
849  const uint bases_len,
850  int *r_base_index,
851  BMVert **r_eve,
852  BMEdge **r_eed,
853  BMFace **r_efa)
854 {
855  BMEditMesh *em = vc->em;
856 
857  const bool use_cycle = !WM_cursor_test_motion_and_update(vc->mval);
858  const float dist_init = ED_view3d_select_dist_px();
859  /* since edges select lines, we give dots advantage of ~20 pix */
860  const float dist_margin = (dist_init / 2);
861  float dist = dist_init;
862 
863  struct {
864  struct {
865  BMVert *ele;
866  int base_index;
867  } v;
868  struct {
869  BMEdge *ele;
870  int base_index;
871  } e, e_zbuf;
872  struct {
873  BMFace *ele;
874  int base_index;
875  } f, f_zbuf;
876  } hit = {{NULL}};
877 
878  /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
879 
880  if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_FACE)) {
881  float dist_center = 0.0f;
882  float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ?
883  &dist_center :
884  NULL;
885 
886  uint base_index = 0;
887  BMFace *efa_zbuf = NULL;
888  BMFace *efa_test = EDBM_face_find_nearest_ex(
889  vc, &dist, dist_center_p, true, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index);
890 
891  if (efa_test && dist_center_p) {
892  dist = min_ff(dist_margin, dist_center);
893  }
894  if (efa_test) {
895  hit.f.base_index = base_index;
896  hit.f.ele = efa_test;
897  }
898  if (efa_zbuf) {
899  hit.f_zbuf.base_index = base_index;
900  hit.f_zbuf.ele = efa_zbuf;
901  }
902  }
903 
904  if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
905  float dist_center = 0.0f;
906  float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
907 
908  uint base_index = 0;
909  BMEdge *eed_zbuf = NULL;
910  BMEdge *eed_test = EDBM_edge_find_nearest_ex(
911  vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf, bases, bases_len, &base_index);
912 
913  if (eed_test && dist_center_p) {
914  dist = min_ff(dist_margin, dist_center);
915  }
916  if (eed_test) {
917  hit.e.base_index = base_index;
918  hit.e.ele = eed_test;
919  }
920  if (eed_zbuf) {
921  hit.e_zbuf.base_index = base_index;
922  hit.e_zbuf.ele = eed_zbuf;
923  }
924  }
925 
926  if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_VERTEX)) {
927  uint base_index = 0;
928  BMVert *eve_test = EDBM_vert_find_nearest_ex(
929  vc, &dist, true, use_cycle, bases, bases_len, &base_index);
930 
931  if (eve_test) {
932  hit.v.base_index = base_index;
933  hit.v.ele = eve_test;
934  }
935  }
936 
937  /* Return only one of 3 pointers, for front-buffer redraws. */
938  if (hit.v.ele) {
939  hit.f.ele = NULL;
940  hit.e.ele = NULL;
941  }
942  else if (hit.e.ele) {
943  hit.f.ele = NULL;
944  }
945 
946  /* there may be a face under the cursor, who's center if too far away
947  * use this if all else fails, it makes sense to select this */
948  if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) {
949  if (hit.e_zbuf.ele) {
950  hit.e.base_index = hit.e_zbuf.base_index;
951  hit.e.ele = hit.e_zbuf.ele;
952  }
953  else if (hit.f_zbuf.ele) {
954  hit.f.base_index = hit.f_zbuf.base_index;
955  hit.f.ele = hit.f_zbuf.ele;
956  }
957  }
958 
959  /* Only one element type will be non-null. */
960  BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1);
961 
962  if (hit.v.ele) {
963  *r_base_index = hit.v.base_index;
964  }
965  if (hit.e.ele) {
966  *r_base_index = hit.e.base_index;
967  }
968  if (hit.f.ele) {
969  *r_base_index = hit.f.base_index;
970  }
971 
972  *r_eve = hit.v.ele;
973  *r_eed = hit.e.ele;
974  *r_efa = hit.f.ele;
975 
976  return (hit.v.ele || hit.e.ele || hit.f.ele);
977 }
978 
979 #undef FAKE_SELECT_MODE_BEGIN
980 #undef FAKE_SELECT_MODE_END
981 
983  Base **bases,
984  const uint bases_len,
985  int *r_base_index,
986  BMVert **r_eve,
987  BMEdge **r_eed,
988  BMFace **r_efa)
989 {
990  return unified_findnearest(vc, bases, bases_len, r_base_index, r_eve, r_eed, r_efa);
991 }
992 
995 /* -------------------------------------------------------------------- */
1003  Base **bases,
1004  const uint bases_len,
1005  bool use_boundary_vertices,
1006  bool use_boundary_edges,
1007  int *r_base_index_vert,
1008  int *r_base_index_edge,
1009  int *r_base_index_face,
1010  struct BMVert **r_eve,
1011  struct BMEdge **r_eed,
1012  struct BMFace **r_efa)
1013 {
1014 
1015  const float mval_fl[2] = {UNPACK2(vc->mval)};
1016  float ray_origin[3], ray_direction[3];
1017 
1018  struct {
1019  uint base_index;
1020  BMElem *ele;
1021  } best = {0, NULL};
1022  /* Currently unused, keep since we may want to pick the best. */
1023  UNUSED_VARS(best);
1024 
1025  struct {
1026  uint base_index;
1027  BMElem *ele;
1028  } best_vert = {0, NULL};
1029 
1030  struct {
1031  uint base_index;
1032  BMElem *ele;
1033  } best_edge = {0, NULL};
1034 
1035  struct {
1036  uint base_index;
1037  BMElem *ele;
1038  } best_face = {0, NULL};
1039 
1041  vc->depsgraph, vc->region, vc->v3d, mval_fl, ray_origin, ray_direction, true)) {
1042  float dist_sq_best = FLT_MAX;
1043  float dist_sq_best_vert = FLT_MAX;
1044  float dist_sq_best_edge = FLT_MAX;
1045  float dist_sq_best_face = FLT_MAX;
1046 
1047  const bool use_vert = (r_eve != NULL);
1048  const bool use_edge = (r_eed != NULL);
1049  const bool use_face = (r_efa != NULL);
1050 
1051  for (uint base_index = 0; base_index < bases_len; base_index++) {
1052  Base *base_iter = bases[base_index];
1053  Object *obedit = base_iter->object;
1054 
1055  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1056  BMesh *bm = em->bm;
1057  float imat3[3][3];
1058 
1060  copy_m3_m4(imat3, obedit->obmat);
1061  invert_m3(imat3);
1062 
1063  const float(*coords)[3] = NULL;
1064  {
1065  Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data);
1066  if (me_eval->runtime.edit_data) {
1067  coords = me_eval->runtime.edit_data->vertexCos;
1068  }
1069  }
1070 
1071  if (coords != NULL) {
1073  }
1074 
1075  if ((use_boundary_vertices || use_boundary_edges) && (use_vert || use_edge)) {
1076  BMEdge *e;
1077  BMIter eiter;
1078  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
1079  if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && (BM_edge_is_boundary(e))) {
1080  if (use_vert && use_boundary_vertices) {
1081  for (uint j = 0; j < 2; j++) {
1082  BMVert *v = *((&e->v1) + j);
1083  float point[3];
1084  mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
1085  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1086  ray_origin, ray_direction, point);
1087  if (dist_sq_test < dist_sq_best_vert) {
1088  dist_sq_best_vert = dist_sq_test;
1089  best_vert.base_index = base_index;
1090  best_vert.ele = (BMElem *)v;
1091  }
1092  if (dist_sq_test < dist_sq_best) {
1093  dist_sq_best = dist_sq_test;
1094  best.base_index = base_index;
1095  best.ele = (BMElem *)v;
1096  }
1097  }
1098  }
1099 
1100  if (use_edge && use_boundary_edges) {
1101  float point[3];
1102 #if 0
1103  const float dist_sq_test = dist_squared_ray_to_seg_v3(
1104  ray_origin, ray_direction, e->v1->co, e->v2->co, point, &depth);
1105 #else
1106  if (coords) {
1107  mid_v3_v3v3(
1108  point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
1109  }
1110  else {
1111  mid_v3_v3v3(point, e->v1->co, e->v2->co);
1112  }
1113  mul_m4_v3(obedit->obmat, point);
1114  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1115  ray_origin, ray_direction, point);
1116  if (dist_sq_test < dist_sq_best_edge) {
1117  dist_sq_best_edge = dist_sq_test;
1118  best_edge.base_index = base_index;
1119  best_edge.ele = (BMElem *)e;
1120  }
1121  if (dist_sq_test < dist_sq_best) {
1122  dist_sq_best = dist_sq_test;
1123  best.base_index = base_index;
1124  best.ele = (BMElem *)e;
1125  }
1126 #endif
1127  }
1128  }
1129  }
1130  }
1131  /* Non boundary case. */
1132  if (use_vert && !use_boundary_vertices) {
1133  BMVert *v;
1134  BMIter viter;
1135  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
1136  if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
1137  float point[3];
1138  mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
1139  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1140  ray_origin, ray_direction, point);
1141  if (dist_sq_test < dist_sq_best_vert) {
1142  dist_sq_best_vert = dist_sq_test;
1143  best_vert.base_index = base_index;
1144  best_vert.ele = (BMElem *)v;
1145  }
1146  if (dist_sq_test < dist_sq_best) {
1147  dist_sq_best = dist_sq_test;
1148  best.base_index = base_index;
1149  best.ele = (BMElem *)v;
1150  }
1151  }
1152  }
1153  }
1154 
1155  if (use_edge && !use_boundary_edges) {
1156  BMEdge *e;
1157  BMIter eiter;
1158  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
1159  if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
1160  float point[3];
1161  if (coords) {
1162  mid_v3_v3v3(
1163  point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
1164  }
1165  else {
1166  mid_v3_v3v3(point, e->v1->co, e->v2->co);
1167  }
1168  mul_m4_v3(obedit->obmat, point);
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_edge) {
1172  dist_sq_best_edge = dist_sq_test;
1173  best_edge.base_index = base_index;
1174  best_edge.ele = (BMElem *)e;
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 *)e;
1180  }
1181  }
1182  }
1183  }
1184 
1185  if (use_face) {
1186  BMFace *f;
1187  BMIter fiter;
1188  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
1189  if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == false) {
1190  float point[3];
1191  if (coords) {
1193  }
1194  else {
1196  }
1197  mul_m4_v3(obedit->obmat, point);
1198  const float dist_sq_test = dist_squared_to_ray_v3_normalized(
1199  ray_origin, ray_direction, point);
1200  if (dist_sq_test < dist_sq_best_face) {
1201  dist_sq_best_face = dist_sq_test;
1202  best_face.base_index = base_index;
1203  best_face.ele = (BMElem *)f;
1204  }
1205  if (dist_sq_test < dist_sq_best) {
1206  dist_sq_best = dist_sq_test;
1207  best.base_index = base_index;
1208  best.ele = (BMElem *)f;
1209  }
1210  }
1211  }
1212  }
1213  }
1214  }
1215 
1216  *r_base_index_vert = best_vert.base_index;
1217  *r_base_index_edge = best_edge.base_index;
1218  *r_base_index_face = best_face.base_index;
1219 
1220  if (r_eve) {
1221  *r_eve = NULL;
1222  }
1223  if (r_eed) {
1224  *r_eed = NULL;
1225  }
1226  if (r_efa) {
1227  *r_efa = NULL;
1228  }
1229 
1230  if (best_vert.ele) {
1231  *r_eve = (BMVert *)best_vert.ele;
1232  }
1233  if (best_edge.ele) {
1234  *r_eed = (BMEdge *)best_edge.ele;
1235  }
1236  if (best_face.ele) {
1237  *r_efa = (BMFace *)best_face.ele;
1238  }
1239 
1240  return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL);
1241 }
1242 
1245 /* -------------------------------------------------------------------- */
1250 {
1251  Object *obedit = CTX_data_edit_object(C);
1252  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1253  BMesh *bm = em->bm;
1254  bool changed = false;
1255 
1256  /* group vars */
1257  int *groups_array;
1258  int(*group_index)[2];
1259  int group_tot;
1260  int i;
1261 
1262  if (bm->totfacesel < 2) {
1263  BKE_report(op->reports, RPT_ERROR, "No face regions selected");
1264  return OPERATOR_CANCELLED;
1265  }
1266 
1267  groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
1268  group_tot = BM_mesh_calc_face_groups(
1269  bm, groups_array, &group_index, NULL, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
1270 
1272 
1273  for (i = 0; i < group_tot; i++) {
1274  ListBase faces_regions;
1275  int tot;
1276 
1277  const int fg_sta = group_index[i][0];
1278  const int fg_len = group_index[i][1];
1279  int j;
1280  BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__);
1281 
1282  for (j = 0; j < fg_len; j++) {
1283  fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
1284  }
1285 
1286  tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions);
1287 
1288  MEM_freeN(fg);
1289 
1290  if (tot) {
1291  LinkData *link;
1292  while ((link = BLI_pophead(&faces_regions))) {
1293  BMFace *f, **faces = link->data;
1294  while ((f = *(faces++))) {
1295  BM_face_select_set(bm, f, true);
1296  }
1297  MEM_freeN(link->data);
1298  MEM_freeN(link);
1299 
1300  changed = true;
1301  }
1302  }
1303  }
1304 
1305  MEM_freeN(groups_array);
1306  MEM_freeN(group_index);
1307 
1308  if (changed) {
1311  }
1312  else {
1313  BKE_report(op->reports, RPT_WARNING, "No matching face regions found");
1314  }
1315 
1316  return OPERATOR_FINISHED;
1317 }
1318 
1320 {
1321  /* identifiers */
1322  ot->name = "Select Similar Regions";
1323  ot->idname = "MESH_OT_select_similar_region";
1324  ot->description = "Select similar face regions to the current selection";
1325 
1326  /* api callbacks */
1329 
1330  /* flags */
1332 }
1333 
1336 /* -------------------------------------------------------------------- */
1341 {
1342  const int type = RNA_enum_get(op->ptr, "type");
1343  const int action = RNA_enum_get(op->ptr, "action");
1344  const bool use_extend = RNA_boolean_get(op->ptr, "use_extend");
1345  const bool use_expand = RNA_boolean_get(op->ptr, "use_expand");
1346 
1347  if (EDBM_selectmode_toggle_multi(C, type, action, use_extend, use_expand)) {
1348  return OPERATOR_FINISHED;
1349  }
1350  return OPERATOR_CANCELLED;
1351 }
1352 
1353 static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1354 {
1355  /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */
1356  if (CTX_wm_space_image(C)) {
1358  if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
1359  return OPERATOR_PASS_THROUGH;
1360  }
1361  /* Bypass when no action is needed. */
1362  if (!RNA_struct_property_is_set(op->ptr, "type")) {
1363  return OPERATOR_CANCELLED;
1364  }
1365  }
1366 
1367  /* detecting these options based on shift/ctrl here is weak, but it's done
1368  * to make this work when clicking buttons or menus */
1369  if (!RNA_struct_property_is_set(op->ptr, "use_extend")) {
1370  RNA_boolean_set(op->ptr, "use_extend", event->modifier & KM_SHIFT);
1371  }
1372  if (!RNA_struct_property_is_set(op->ptr, "use_expand")) {
1373  RNA_boolean_set(op->ptr, "use_expand", event->modifier & KM_CTRL);
1374  }
1375 
1376  return edbm_select_mode_exec(C, op);
1377 }
1378 
1380  struct wmOperatorType *UNUSED(op),
1381  struct PointerRNA *values)
1382 {
1383  const int type = RNA_enum_get(values, "type");
1384 
1385  /* Because the special behavior for shift and ctrl click depend on user input, they may be
1386  * incorrect if the operator is used from a script or from a special button. So only return the
1387  * specialized descriptions if only the "type" is set, which conveys that the operator is meant
1388  * to be used with the logic in the `invoke` method. */
1389  if (RNA_struct_property_is_set(values, "type") &&
1390  !RNA_struct_property_is_set(values, "use_extend") &&
1391  !RNA_struct_property_is_set(values, "use_expand") &&
1392  !RNA_struct_property_is_set(values, "action")) {
1393  switch (type) {
1394  case SCE_SELECT_VERTEX:
1395  return BLI_strdup(TIP_(
1396  "Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection"));
1397  case SCE_SELECT_EDGE:
1398  return BLI_strdup(
1399  TIP_("Edge select - Shift-Click for multiple modes, "
1400  "Ctrl-Click expands/contracts selection depending on the current mode"));
1401  case SCE_SELECT_FACE:
1402  return BLI_strdup(
1403  TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
1404  }
1405  }
1406 
1407  return NULL;
1408 }
1409 
1411 {
1412  PropertyRNA *prop;
1413 
1414  static const EnumPropertyItem actions_items[] = {
1415  {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1416  {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1417  {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1418  {0, NULL, 0, NULL, NULL},
1419  };
1420 
1421  /* identifiers */
1422  ot->name = "Select Mode";
1423  ot->idname = "MESH_OT_select_mode";
1424  ot->description = "Change selection mode";
1425 
1426  /* api callbacks */
1431 
1432  /* flags */
1434 
1435  /* properties */
1436  /* Hide all, not to show redo panel. */
1437  prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", "");
1439  prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", "");
1441  ot->prop = prop = RNA_def_enum(ot->srna, "type", rna_enum_mesh_select_mode_items, 0, "Type", "");
1443 
1444  prop = RNA_def_enum(
1445  ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
1447 }
1448 
1451 /* -------------------------------------------------------------------- */
1456  int walkercode,
1457  void *start,
1458  int r_count_by_select[2])
1459 {
1460  BMesh *bm = em->bm;
1461  BMElem *ele;
1462  BMWalker walker;
1463 
1464  r_count_by_select[0] = r_count_by_select[1] = 0;
1465 
1466  BMW_init(&walker,
1467  bm,
1468  walkercode,
1469  BMW_MASK_NOP,
1470  BMW_MASK_NOP,
1471  BMW_MASK_NOP,
1473  BMW_NIL_LAY);
1474 
1475  for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1476  r_count_by_select[BM_elem_flag_test(ele, BM_ELEM_SELECT) ? 1 : 0] += 1;
1477 
1478  /* Early exit when mixed (could be optional if needed. */
1479  if (r_count_by_select[0] && r_count_by_select[1]) {
1480  r_count_by_select[0] = r_count_by_select[1] = -1;
1481  break;
1482  }
1483  }
1484 
1485  BMW_end(&walker);
1486 }
1487 
1488 static void walker_select(BMEditMesh *em, int walkercode, void *start, const bool select)
1489 {
1490  BMesh *bm = em->bm;
1491  BMElem *ele;
1492  BMWalker walker;
1493 
1494  BMW_init(&walker,
1495  bm,
1496  walkercode,
1497  BMW_MASK_NOP,
1498  BMW_MASK_NOP,
1499  BMW_MASK_NOP,
1501  BMW_NIL_LAY);
1502 
1503  for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1504  if (!select) {
1506  }
1507  BM_elem_select_set(bm, ele, select);
1508  }
1509  BMW_end(&walker);
1510 }
1511 
1513 {
1514  const bool is_ring = RNA_boolean_get(op->ptr, "ring");
1515  ViewLayer *view_layer = CTX_data_view_layer(C);
1516  uint objects_len = 0;
1518  view_layer, CTX_wm_view3d(C), &objects_len);
1519  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1520  Object *obedit = objects[ob_index];
1521  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1522 
1523  if (em->bm->totedgesel == 0) {
1524  continue;
1525  }
1526 
1527  BMEdge *eed;
1528  BMEdge **edarray;
1529  int edindex;
1530  BMIter iter;
1531  int totedgesel = 0;
1532 
1533  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1534  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1535  totedgesel++;
1536  }
1537  }
1538 
1539  edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
1540  edindex = 0;
1541 
1542  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1543  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1544  edarray[edindex] = eed;
1545  edindex++;
1546  }
1547  }
1548 
1549  if (is_ring) {
1550  for (edindex = 0; edindex < totedgesel; edindex += 1) {
1551  eed = edarray[edindex];
1552  walker_select(em, BMW_EDGERING, eed, true);
1553  }
1555  }
1556  else {
1557  for (edindex = 0; edindex < totedgesel; edindex += 1) {
1558  eed = edarray[edindex];
1559  bool non_manifold = BM_edge_face_count_is_over(eed, 2);
1560  if (non_manifold) {
1561  walker_select(em, BMW_EDGELOOP_NONMANIFOLD, eed, true);
1562  }
1563  else {
1564  walker_select(em, BMW_EDGELOOP, eed, true);
1565  }
1566  }
1568  }
1569  MEM_freeN(edarray);
1570  // if (EM_texFaceCheck())
1571 
1574  }
1575  MEM_freeN(objects);
1576 
1577  return OPERATOR_FINISHED;
1578 }
1579 
1581 {
1582  /* identifiers */
1583  ot->name = "Multi Select Loops";
1584  ot->idname = "MESH_OT_loop_multi_select";
1585  ot->description = "Select a loop of connected edges by connection type";
1586 
1587  /* api callbacks */
1590 
1591  /* flags */
1593 
1594  /* properties */
1595  RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1596 }
1597 
1600 /* -------------------------------------------------------------------- */
1604 static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1605 {
1606  if (select_clear) {
1608  }
1609 
1610  walker_select(em, BMW_FACELOOP, eed, select);
1611 }
1612 
1613 static void mouse_mesh_loop_edge_ring(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1614 {
1615  if (select_clear) {
1617  }
1618 
1619  walker_select(em, BMW_EDGERING, eed, select);
1620 }
1621 
1623  BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle)
1624 {
1625  bool edge_boundary = false;
1626  bool non_manifold = BM_edge_face_count_is_over(eed, 2);
1627 
1628  /* Cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY. */
1629  if (select_cycle && BM_edge_is_boundary(eed)) {
1630  int count_by_select[2];
1631 
1632  /* If the loops selected toggle the boundaries. */
1633  walker_select_count(em, BMW_EDGELOOP, eed, count_by_select);
1634  if (count_by_select[!select] == 0) {
1635  edge_boundary = true;
1636 
1637  /* If the boundaries selected, toggle back to the loop. */
1638  walker_select_count(em, BMW_EDGEBOUNDARY, eed, count_by_select);
1639  if (count_by_select[!select] == 0) {
1640  edge_boundary = false;
1641  }
1642  }
1643  }
1644 
1645  if (select_clear) {
1647  }
1648 
1649  if (edge_boundary) {
1651  }
1652  else if (non_manifold) {
1654  }
1655  else {
1656  walker_select(em, BMW_EDGELOOP, eed, select);
1657  }
1658 }
1659 
1660 static bool mouse_mesh_loop(
1661  bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
1662 {
1663  Base *basact = NULL;
1664  BMVert *eve = NULL;
1665  BMEdge *eed = NULL;
1666  BMFace *efa = NULL;
1667 
1668  ViewContext vc;
1669  BMEditMesh *em;
1670  bool select = true;
1671  bool select_clear = false;
1672  bool select_cycle = true;
1673  float mvalf[2];
1674 
1675  em_setup_viewcontext(C, &vc);
1676  mvalf[0] = (float)(vc.mval[0] = mval[0]);
1677  mvalf[1] = (float)(vc.mval[1] = mval[1]);
1678 
1679  BMEditMesh *em_original = vc.em;
1680  const short selectmode = em_original->selectmode;
1681  em_original->selectmode = SCE_SELECT_EDGE;
1682 
1683  uint bases_len;
1684  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
1685 
1686  {
1687  int base_index = -1;
1688  if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) {
1689  basact = bases[base_index];
1691  em = vc.em;
1692  }
1693  else {
1694  em = NULL;
1695  }
1696  }
1697 
1698  em_original->selectmode = selectmode;
1699 
1700  if (em == NULL || eed == NULL) {
1701  MEM_freeN(bases);
1702  return false;
1703  }
1704 
1705  if (extend == false && deselect == false && toggle == false) {
1706  select_clear = true;
1707  }
1708 
1709  if (extend) {
1710  select = true;
1711  }
1712  else if (deselect) {
1713  select = false;
1714  }
1715  else if (select_clear || (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0)) {
1716  select = true;
1717  }
1718  else if (toggle) {
1719  select = false;
1720  select_cycle = false;
1721  }
1722 
1723  if (select_clear) {
1724  for (uint base_index = 0; base_index < bases_len; base_index++) {
1725  Base *base_iter = bases[base_index];
1726  Object *ob_iter = base_iter->object;
1727  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
1728 
1729  if (em_iter->bm->totvertsel == 0) {
1730  continue;
1731  }
1732 
1733  if (em_iter == em) {
1734  continue;
1735  }
1736 
1739  }
1740  }
1741 
1742  if (em->selectmode & SCE_SELECT_FACE) {
1743  mouse_mesh_loop_face(em, eed, select, select_clear);
1744  }
1745  else {
1746  if (ring) {
1747  mouse_mesh_loop_edge_ring(em, eed, select, select_clear);
1748  }
1749  else {
1750  mouse_mesh_loop_edge(em, eed, select, select_clear, select_cycle);
1751  }
1752  }
1753 
1755 
1756  /* sets as active, useful for other tools */
1757  if (select) {
1758  if (em->selectmode & SCE_SELECT_VERTEX) {
1759  /* Find nearest vert from mouse
1760  * (initialize to large values in case only one vertex can be projected) */
1761  float v1_co[2], v2_co[2];
1762  float length_1 = FLT_MAX;
1763  float length_2 = FLT_MAX;
1764 
1765  /* We can't be sure this has already been set... */
1767 
1769  V3D_PROJ_RET_OK) {
1770  length_1 = len_squared_v2v2(mvalf, v1_co);
1771  }
1772 
1774  V3D_PROJ_RET_OK) {
1775  length_2 = len_squared_v2v2(mvalf, v2_co);
1776  }
1777 #if 0
1778  printf("mouse to v1: %f\nmouse to v2: %f\n",
1779  len_squared_v2v2(mvalf, v1_co),
1780  len_squared_v2v2(mvalf, v2_co));
1781 #endif
1782  BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2);
1783  }
1784  else if (em->selectmode & SCE_SELECT_EDGE) {
1785  BM_select_history_store(em->bm, eed);
1786  }
1787  else if (em->selectmode & SCE_SELECT_FACE) {
1788  /* Select the face of eed which is the nearest of mouse. */
1789  BMFace *f;
1790  BMIter iterf;
1791  float best_dist = FLT_MAX;
1792  efa = NULL;
1793 
1794  /* We can't be sure this has already been set... */
1796 
1797  BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) {
1799  float cent[3];
1800  float co[2], tdist;
1801 
1802  BM_face_calc_center_median(f, cent);
1804  V3D_PROJ_RET_OK) {
1805  tdist = len_squared_v2v2(mvalf, co);
1806  if (tdist < best_dist) {
1807  // printf("Best face: %p (%f)\n", f, tdist);
1808  best_dist = tdist;
1809  efa = f;
1810  }
1811  }
1812  }
1813  }
1814  if (efa) {
1815  BM_mesh_active_face_set(em->bm, efa);
1816  BM_select_history_store(em->bm, efa);
1817  }
1818  }
1819  }
1820 
1821  MEM_freeN(bases);
1822 
1825 
1826  return true;
1827 }
1828 
1829 static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1830 {
1831 
1833 
1834  if (mouse_mesh_loop(C,
1835  event->mval,
1836  RNA_boolean_get(op->ptr, "extend"),
1837  RNA_boolean_get(op->ptr, "deselect"),
1838  RNA_boolean_get(op->ptr, "toggle"),
1839  RNA_boolean_get(op->ptr, "ring"))) {
1840  return OPERATOR_FINISHED;
1841  }
1842  return OPERATOR_CANCELLED;
1843 }
1844 
1846 {
1847  /* identifiers */
1848  ot->name = "Loop Select";
1849  ot->idname = "MESH_OT_loop_select";
1850  ot->description = "Select a loop of connected edges";
1851 
1852  /* api callbacks */
1855 
1856  /* flags */
1857  ot->flag = OPTYPE_UNDO;
1858 
1859  /* properties */
1860  PropertyRNA *prop;
1861 
1862  prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
1864  prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1866  prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1868  prop = RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
1870 }
1871 
1873 {
1874  /* description */
1875  ot->name = "Edge Ring Select";
1876  ot->idname = "MESH_OT_edgering_select";
1877  ot->description = "Select an edge ring";
1878 
1879  /* callbacks */
1882 
1883  /* flags */
1884  ot->flag = OPTYPE_UNDO;
1885 
1886  /* Properties. */
1887  PropertyRNA *prop;
1888  prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1890  prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1892  prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1894  prop = RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
1896 }
1897 
1900 /* -------------------------------------------------------------------- */
1905 {
1906  ViewLayer *view_layer = CTX_data_view_layer(C);
1907  int action = RNA_enum_get(op->ptr, "action");
1908 
1909  uint objects_len = 0;
1911  view_layer, CTX_wm_view3d(C), &objects_len);
1912 
1913  if (action == SEL_TOGGLE) {
1914  action = SEL_SELECT;
1915  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1916  Object *obedit = objects[ob_index];
1917  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1918  if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) {
1919  action = SEL_DESELECT;
1920  break;
1921  }
1922  }
1923  }
1924 
1925  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1926  Object *obedit = objects[ob_index];
1927  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1928  switch (action) {
1929  case SEL_SELECT:
1931  break;
1932  case SEL_DESELECT:
1934  break;
1935  case SEL_INVERT:
1936  EDBM_select_swap(em);
1938  break;
1939  }
1942  }
1943 
1944  MEM_freeN(objects);
1945 
1946  return OPERATOR_FINISHED;
1947 }
1948 
1950 {
1951  /* identifiers */
1952  ot->name = "(De)select All";
1953  ot->idname = "MESH_OT_select_all";
1954  ot->description = "(De)select all vertices, edges or faces";
1955 
1956  /* api callbacks */
1959 
1960  /* flags */
1962 
1964 }
1965 
1968 /* -------------------------------------------------------------------- */
1973 {
1974  ViewLayer *view_layer = CTX_data_view_layer(C);
1975  uint objects_len = 0;
1977  view_layer, CTX_wm_view3d(C), &objects_len);
1978 
1979  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1980  Object *obedit = objects[ob_index];
1981  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1982 
1983  if (!EDBM_select_interior_faces(em)) {
1984  continue;
1985  }
1986 
1989  }
1990  MEM_freeN(objects);
1991 
1992  return OPERATOR_FINISHED;
1993 }
1994 
1996 {
1997  /* identifiers */
1998  ot->name = "Select Interior Faces";
1999  ot->idname = "MESH_OT_select_interior_faces";
2000  ot->description = "Select faces where all edges have more than 2 face users";
2001 
2002  /* api callbacks */
2005 
2006  /* flags */
2008 }
2009 
2012 /* -------------------------------------------------------------------- */
2019 bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
2020 {
2021  ViewContext vc;
2022 
2023  int base_index_active = -1;
2024  BMVert *eve = NULL;
2025  BMEdge *eed = NULL;
2026  BMFace *efa = NULL;
2027 
2028  /* setup view context for argument to callbacks */
2029  em_setup_viewcontext(C, &vc);
2030  vc.mval[0] = mval[0];
2031  vc.mval[1] = mval[1];
2032 
2033  uint bases_len = 0;
2034  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
2035 
2036  bool changed = false;
2037  bool found = unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa);
2038 
2039  if (params->sel_op == SEL_OP_SET) {
2040  BMElem *ele = efa ? (BMElem *)efa : (eed ? (BMElem *)eed : (BMElem *)eve);
2041  if ((found && params->select_passthrough) && BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
2042  found = false;
2043  }
2044  else if (found || params->deselect_all) {
2045  /* Deselect everything. */
2046  for (uint base_index = 0; base_index < bases_len; base_index++) {
2047  Base *base_iter = bases[base_index];
2048  Object *ob_iter = base_iter->object;
2052  }
2053  changed = true;
2054  }
2055  }
2056 
2057  if (found) {
2058  Base *basact = bases[base_index_active];
2060 
2061  if (efa) {
2062  switch (params->sel_op) {
2063  case SEL_OP_ADD: {
2064  BM_mesh_active_face_set(vc.em->bm, efa);
2065 
2066  /* Work-around: deselect first, so we can guarantee it will
2067  * be active even if it was already selected. */
2068  BM_select_history_remove(vc.em->bm, efa);
2069  BM_face_select_set(vc.em->bm, efa, false);
2070  BM_select_history_store(vc.em->bm, efa);
2071  BM_face_select_set(vc.em->bm, efa, true);
2072  break;
2073  }
2074  case SEL_OP_SUB: {
2075  BM_select_history_remove(vc.em->bm, efa);
2076  BM_face_select_set(vc.em->bm, efa, false);
2077  break;
2078  }
2079  case SEL_OP_XOR: {
2080  BM_mesh_active_face_set(vc.em->bm, efa);
2081  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2082  BM_select_history_store(vc.em->bm, efa);
2083  BM_face_select_set(vc.em->bm, efa, true);
2084  }
2085  else {
2086  BM_select_history_remove(vc.em->bm, efa);
2087  BM_face_select_set(vc.em->bm, efa, false);
2088  }
2089  break;
2090  }
2091  case SEL_OP_SET: {
2092  BM_mesh_active_face_set(vc.em->bm, efa);
2093  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2094  BM_select_history_store(vc.em->bm, efa);
2095  BM_face_select_set(vc.em->bm, efa, true);
2096  }
2097  break;
2098  }
2099  case SEL_OP_AND: {
2100  BLI_assert_unreachable(); /* Doesn't make sense for picking. */
2101  break;
2102  }
2103  }
2104  }
2105  else if (eed) {
2106 
2107  switch (params->sel_op) {
2108  case SEL_OP_ADD: {
2109  /* Work-around: deselect first, so we can guarantee it will
2110  * be active even if it was already selected. */
2111  BM_select_history_remove(vc.em->bm, eed);
2112  BM_edge_select_set(vc.em->bm, eed, false);
2113  BM_select_history_store(vc.em->bm, eed);
2114  BM_edge_select_set(vc.em->bm, eed, true);
2115  break;
2116  }
2117  case SEL_OP_SUB: {
2118  BM_select_history_remove(vc.em->bm, eed);
2119  BM_edge_select_set(vc.em->bm, eed, false);
2120  break;
2121  }
2122  case SEL_OP_XOR: {
2123  if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2124  BM_select_history_store(vc.em->bm, eed);
2125  BM_edge_select_set(vc.em->bm, eed, true);
2126  }
2127  else {
2128  BM_select_history_remove(vc.em->bm, eed);
2129  BM_edge_select_set(vc.em->bm, eed, false);
2130  }
2131  break;
2132  }
2133  case SEL_OP_SET: {
2134  if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2135  BM_select_history_store(vc.em->bm, eed);
2136  BM_edge_select_set(vc.em->bm, eed, true);
2137  }
2138  break;
2139  }
2140  case SEL_OP_AND: {
2141  BLI_assert_unreachable(); /* Doesn't make sense for picking. */
2142  break;
2143  }
2144  }
2145  }
2146  else if (eve) {
2147  switch (params->sel_op) {
2148  case SEL_OP_ADD: {
2149  /* Work-around: deselect first, so we can guarantee it will
2150  * be active even if it was already selected. */
2151  BM_select_history_remove(vc.em->bm, eve);
2152  BM_vert_select_set(vc.em->bm, eve, false);
2153  BM_select_history_store(vc.em->bm, eve);
2154  BM_vert_select_set(vc.em->bm, eve, true);
2155  break;
2156  }
2157  case SEL_OP_SUB: {
2158  BM_select_history_remove(vc.em->bm, eve);
2159  BM_vert_select_set(vc.em->bm, eve, false);
2160  break;
2161  }
2162  case SEL_OP_XOR: {
2163  if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
2164  BM_select_history_store(vc.em->bm, eve);
2165  BM_vert_select_set(vc.em->bm, eve, true);
2166  }
2167  else {
2168  BM_select_history_remove(vc.em->bm, eve);
2169  BM_vert_select_set(vc.em->bm, eve, false);
2170  }
2171  break;
2172  }
2173  case SEL_OP_SET: {
2174  if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
2175  BM_select_history_store(vc.em->bm, eve);
2176  BM_vert_select_set(vc.em->bm, eve, true);
2177  }
2178  break;
2179  }
2180  case SEL_OP_AND: {
2181  BLI_assert_unreachable(); /* Doesn't make sense for picking. */
2182  break;
2183  }
2184  }
2185  }
2186 
2188 
2189  if (efa) {
2190  /* Change active material on object. */
2191  if (efa->mat_nr != vc.obedit->actcol - 1) {
2192  vc.obedit->actcol = efa->mat_nr + 1;
2193  vc.em->mat_nr = efa->mat_nr;
2195  }
2196 
2197  /* Change active face-map on object. */
2198  if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) {
2199  const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP);
2200  if (cd_fmap_offset != -1) {
2201  int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset));
2202  if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) {
2203  map = -1;
2204  }
2205  map += 1;
2206  if (map != vc.obedit->actfmap) {
2207  /* We may want to add notifiers later,
2208  * currently select update handles redraw. */
2209  vc.obedit->actfmap = map;
2210  }
2211  }
2212  }
2213  }
2214 
2215  /* Changing active object is handy since it allows us to
2216  * switch UV layers, vgroups for eg. */
2217  if (vc.view_layer->basact != basact) {
2218  ED_object_base_activate(C, basact);
2219  }
2220 
2223 
2224  changed = true;
2225  }
2226 
2227  MEM_freeN(bases);
2228 
2229  return changed;
2230 }
2231 
2234 /* -------------------------------------------------------------------- */
2239 {
2240  BMEditSelection *ese, *nextese;
2241 
2242  if (!(em->selectmode & SCE_SELECT_VERTEX)) {
2243  ese = em->bm->selected.first;
2244  while (ese) {
2245  nextese = ese->next;
2246  if (ese->htype == BM_VERT) {
2247  BLI_freelinkN(&(em->bm->selected), ese);
2248  }
2249  ese = nextese;
2250  }
2251  }
2252  if (!(em->selectmode & SCE_SELECT_EDGE)) {
2253  ese = em->bm->selected.first;
2254  while (ese) {
2255  nextese = ese->next;
2256  if (ese->htype == BM_EDGE) {
2257  BLI_freelinkN(&(em->bm->selected), ese);
2258  }
2259  ese = nextese;
2260  }
2261  }
2262  if (!(em->selectmode & SCE_SELECT_FACE)) {
2263  ese = em->bm->selected.first;
2264  while (ese) {
2265  nextese = ese->next;
2266  if (ese->htype == BM_FACE) {
2267  BLI_freelinkN(&(em->bm->selected), ese);
2268  }
2269  ese = nextese;
2270  }
2271  }
2272 }
2273 
2275 {
2276  BMVert *eve;
2277  BMEdge *eed;
2278  BMFace *efa;
2279  BMIter iter;
2280 
2281  em->bm->selectmode = em->selectmode;
2282 
2283  /* strip BMEditSelections from em->selected that are not relevant to new mode */
2285 
2286  if (em->bm->totvertsel == 0 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
2287  return;
2288  }
2289 
2290  if (em->selectmode & SCE_SELECT_VERTEX) {
2291  if (em->bm->totvertsel) {
2292  EDBM_select_flush(em);
2293  }
2294  }
2295  else if (em->selectmode & SCE_SELECT_EDGE) {
2296  /* deselect vertices, and select again based on edge select */
2297  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2298  BM_vert_select_set(em->bm, eve, false);
2299  }
2300 
2301  if (em->bm->totedgesel) {
2302  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2303  if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2304  BM_edge_select_set(em->bm, eed, true);
2305  }
2306  }
2307 
2308  /* selects faces based on edge status */
2310  }
2311  }
2312  else if (em->selectmode & SCE_SELECT_FACE) {
2313  /* Deselect edges, and select again based on face select. */
2314  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2315  BM_edge_select_set(em->bm, eed, false);
2316  }
2317 
2318  if (em->bm->totfacesel) {
2319  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2320  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2321  BM_face_select_set(em->bm, efa, true);
2322  }
2323  }
2324  }
2325  }
2326 }
2327 
2329  const short selectmode_old,
2330  const short selectmode_new)
2331 {
2332  BMesh *bm = em->bm;
2333 
2334  BMVert *eve;
2335  BMEdge *eed;
2336  BMFace *efa;
2337  BMIter iter;
2338 
2339  /* first tag-to-select, then select --- this avoids a feedback loop */
2340 
2341  /* Have to find out what the selection-mode was previously. */
2342  if (selectmode_old == SCE_SELECT_VERTEX) {
2343  if (bm->totvertsel == 0) {
2344  /* pass */
2345  }
2346  else if (selectmode_new == SCE_SELECT_EDGE) {
2347  /* flush up (vert -> edge) */
2348 
2349  /* select all edges associated with every selected vert */
2350  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2352  }
2353 
2354  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2355  if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
2356  BM_edge_select_set(bm, eed, true);
2357  }
2358  }
2359  }
2360  else if (selectmode_new == SCE_SELECT_FACE) {
2361  /* flush up (vert -> face) */
2362 
2363  /* select all faces associated with every selected vert */
2364  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2366  }
2367 
2368  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2369  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2370  BM_face_select_set(bm, efa, true);
2371  }
2372  }
2373  }
2374  }
2375  else if (selectmode_old == SCE_SELECT_EDGE) {
2376  if (bm->totedgesel == 0) {
2377  /* pass */
2378  }
2379  else if (selectmode_new == SCE_SELECT_FACE) {
2380  /* flush up (edge -> face) */
2381 
2382  /* select all faces associated with every selected edge */
2383  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2385  }
2386 
2387  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2388  if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2389  BM_face_select_set(bm, efa, true);
2390  }
2391  }
2392  }
2393  else if (selectmode_new == SCE_SELECT_VERTEX) {
2394  /* flush down (edge -> vert) */
2395 
2396  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2397  if (!BM_vert_is_all_edge_flag_test(eve, BM_ELEM_SELECT, true)) {
2398  BM_vert_select_set(bm, eve, false);
2399  }
2400  }
2401  /* deselect edges without both verts selected */
2403  }
2404  }
2405  else if (selectmode_old == SCE_SELECT_FACE) {
2406  if (bm->totfacesel == 0) {
2407  /* pass */
2408  }
2409  else if (selectmode_new == SCE_SELECT_EDGE) {
2410  /* flush down (face -> edge) */
2411 
2412  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2413  if (!BM_edge_is_all_face_flag_test(eed, BM_ELEM_SELECT, true)) {
2414  BM_edge_select_set(bm, eed, false);
2415  }
2416  }
2417  /* Deselect faces without edges selected. */
2419  }
2420  else if (selectmode_new == SCE_SELECT_VERTEX) {
2421  /* flush down (face -> vert) */
2422 
2423  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2424  if (!BM_vert_is_all_face_flag_test(eve, BM_ELEM_SELECT, true)) {
2425  BM_vert_select_set(bm, eve, false);
2426  }
2427  }
2428  /* deselect faces without verts selected */
2430  }
2431  }
2432 }
2433 
2435  const short selectmode_new,
2436  const int action,
2437  const bool use_extend,
2438  const bool use_expand)
2439 {
2441  ViewLayer *view_layer = CTX_data_view_layer(C);
2443  Object *obedit = CTX_data_edit_object(C);
2444  BMEditMesh *em = NULL;
2445  bool ret = false;
2446 
2447  if (obedit && obedit->type == OB_MESH) {
2448  em = BKE_editmesh_from_object(obedit);
2449  }
2450 
2451  if (em == NULL) {
2452  return ret;
2453  }
2454 
2455  bool only_update = false;
2456  switch (action) {
2457  case -1:
2458  /* already set */
2459  break;
2460  case 0: /* disable */
2461  /* check we have something to do */
2462  if ((em->selectmode & selectmode_new) == 0) {
2463  only_update = true;
2464  break;
2465  }
2466  em->selectmode &= ~selectmode_new;
2467  break;
2468  case 1: /* enable */
2469  /* check we have something to do */
2470  if ((em->selectmode & selectmode_new) != 0) {
2471  only_update = true;
2472  break;
2473  }
2474  em->selectmode |= selectmode_new;
2475  break;
2476  case 2: /* toggle */
2477  /* can't disable this flag if its the only one set */
2478  if (em->selectmode == selectmode_new) {
2479  only_update = true;
2480  break;
2481  }
2482  em->selectmode ^= selectmode_new;
2483  break;
2484  default:
2485  BLI_assert(0);
2486  break;
2487  }
2488 
2489  uint objects_len = 0;
2491  view_layer, CTX_wm_view3d(C), &objects_len);
2492 
2493  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2494  Object *ob_iter = objects[ob_index];
2495  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2496  if (em_iter != em) {
2497  em_iter->selectmode = em->selectmode;
2498  }
2499  }
2500 
2501  if (only_update) {
2502  MEM_freeN(objects);
2503  return false;
2504  }
2505 
2506  if (use_extend == 0 || em->selectmode == 0) {
2507  if (use_expand) {
2508  const short selmode_max = highest_order_bit_s(ts->selectmode);
2509  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2510  Object *ob_iter = objects[ob_index];
2511  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2512  EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new);
2513  }
2514  }
2515  }
2516 
2517  switch (selectmode_new) {
2518  case SCE_SELECT_VERTEX:
2519  if (use_extend == 0 || em->selectmode == 0) {
2521  }
2522  ret = true;
2523  break;
2524  case SCE_SELECT_EDGE:
2525  if (use_extend == 0 || em->selectmode == 0) {
2527  }
2528  ret = true;
2529  break;
2530  case SCE_SELECT_FACE:
2531  if (use_extend == 0 || em->selectmode == 0) {
2533  }
2534  ret = true;
2535  break;
2536  default:
2537  BLI_assert(0);
2538  break;
2539  }
2540 
2541  if (ret == true) {
2542  ts->selectmode = em->selectmode;
2543  em = NULL;
2544  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2545  Object *ob_iter = objects[ob_index];
2546  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2547  em_iter->selectmode = ts->selectmode;
2548  EDBM_selectmode_set(em_iter);
2551  }
2554  }
2555 
2556  MEM_freeN(objects);
2557  return ret;
2558 }
2559 
2560 bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
2561 {
2562  BLI_assert(selectmode != 0);
2563  bool changed = false;
2564 
2565  {
2566  Object *obedit = CTX_data_edit_object(C);
2567  BMEditMesh *em = NULL;
2568  if (obedit && obedit->type == OB_MESH) {
2569  em = BKE_editmesh_from_object(obedit);
2570  }
2571  if (em == NULL) {
2572  return changed;
2573  }
2574  }
2575 
2576  ViewLayer *view_layer = CTX_data_view_layer(C);
2579 
2580  if (ts->selectmode != selectmode) {
2581  ts->selectmode = selectmode;
2582  changed = true;
2583  }
2584 
2585  uint objects_len = 0;
2587  view_layer, CTX_wm_view3d(C), &objects_len);
2588 
2589  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2590  Object *ob_iter = objects[ob_index];
2591  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2592  if (em_iter->selectmode != ts->selectmode) {
2593  em_iter->selectmode = ts->selectmode;
2594  EDBM_selectmode_set(em_iter);
2597  changed = true;
2598  }
2599  }
2600  MEM_freeN(objects);
2601 
2602  if (changed) {
2605  }
2606  return changed;
2607 }
2608 
2610  BMEditMesh *em,
2611  const short selectmode_disable,
2612  const short selectmode_fallback)
2613 {
2614  /* note essential, but switch out of vertex mode since the
2615  * selected regions won't be nicely isolated after flushing */
2616  if (em->selectmode & selectmode_disable) {
2617  if (em->selectmode == selectmode_disable) {
2618  em->selectmode = selectmode_fallback;
2619  }
2620  else {
2621  em->selectmode &= ~selectmode_disable;
2622  }
2624  EDBM_selectmode_set(em);
2625 
2627 
2628  return true;
2629  }
2630  return false;
2631 }
2632 
2635 /* -------------------------------------------------------------------- */
2639 bool EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select)
2640 {
2641  BMIter iter;
2642  BMFace *efa;
2643  bool changed = false;
2644 
2645  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2646  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2647  continue;
2648  }
2649  if (efa->mat_nr == index) {
2650  changed = true;
2651  BM_face_select_set(em->bm, efa, select);
2652  }
2653  }
2654  return changed;
2655 }
2656 
2657 void EDBM_select_toggle_all(BMEditMesh *em) /* exported for UV */
2658 {
2659  if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) {
2661  }
2662  else {
2664  }
2665 }
2666 
2667 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
2668 {
2669  BMIter iter;
2670  BMVert *eve;
2671  BMEdge *eed;
2672  BMFace *efa;
2673 
2674  if (em->bm->selectmode & SCE_SELECT_VERTEX) {
2675  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2676  if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
2677  continue;
2678  }
2680  }
2681  }
2682  else if (em->selectmode & SCE_SELECT_EDGE) {
2683  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2684  if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
2685  continue;
2686  }
2688  }
2689  }
2690  else {
2691  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2692  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
2693  continue;
2694  }
2696  }
2697  }
2698 }
2699 
2700 bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
2701 {
2702  bool changed_multi = false;
2703  for (uint base_index = 0; base_index < bases_len; base_index++) {
2704  Base *base_iter = bases[base_index];
2705  Object *ob_iter = base_iter->object;
2706  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2707 
2708  if (em_iter->bm->totvertsel == 0) {
2709  continue;
2710  }
2711 
2714  changed_multi = true;
2715  }
2716  return changed_multi;
2717 }
2718 
2720 {
2722  ViewContext vc;
2724  uint bases_len = 0;
2726  vc.view_layer, vc.v3d, &bases_len);
2727  bool changed_multi = EDBM_mesh_deselect_all_multi_ex(bases, bases_len);
2728  MEM_freeN(bases);
2729  return changed_multi;
2730 }
2731 
2733  struct Base **bases,
2734  const uint bases_len,
2735  const short selectmode_disable,
2736  const short selectmode_fallback)
2737 {
2738  bool changed_multi = false;
2739  for (uint base_index = 0; base_index < bases_len; base_index++) {
2740  Base *base_iter = bases[base_index];
2741  Object *ob_iter = base_iter->object;
2742  BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2743 
2744  if (EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback)) {
2745  changed_multi = true;
2746  }
2747  }
2748  return changed_multi;
2749 }
2750 
2752  const short selectmode_disable,
2753  const short selectmode_fallback)
2754 {
2757  ViewContext vc;
2759  uint bases_len = 0;
2761  vc.view_layer, NULL, &bases_len);
2762  bool changed_multi = EDBM_selectmode_disable_multi_ex(
2763  scene, bases, bases_len, selectmode_disable, selectmode_fallback);
2764  MEM_freeN(bases);
2765  return changed_multi;
2766 }
2767 
2770 /* -------------------------------------------------------------------- */
2782 struct BMFaceLink {
2783  struct BMFaceLink *next, *prev;
2785  float area;
2786 };
2787 
2789 {
2790  if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
2791  return false;
2792  }
2793  return true;
2794 }
2796  int face_index,
2797  BMLoop *r_l_pair[2])
2798 {
2799 
2800  BMLoop *l_iter = e->l;
2801  int loop_index = 0;
2802  do {
2803  BMFace *f = l_iter->f;
2804  int i = BM_elem_index_get(f);
2805  if (!ELEM(i, -1, face_index)) {
2806  if (loop_index == 2) {
2807  return false;
2808  }
2809  r_l_pair[loop_index++] = l_iter;
2810  }
2811  } while ((l_iter = l_iter->radial_next) != e->l);
2812  return (loop_index == 2);
2813 }
2814 
2819 static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_lengths)
2820 {
2821  /* Dividing by the area is important so larger face groups (which will become the outer shell)
2822  * aren't detected as having a high cost. */
2823  float area = 0.0f;
2824  float cost = 0.0f;
2825  bool found = false;
2826  LISTBASE_FOREACH (struct BMFaceLink *, f_link, ls) {
2827  BMFace *f = f_link->face;
2828  area += f_link->area;
2829  int i = BM_elem_index_get(f);
2830  BLI_assert(i != -1);
2831  BMLoop *l_iter, *l_first;
2832  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2833  do {
2834  if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG)) {
2835  float cost_test = 0.0f;
2836  int cost_count = 0;
2837  /* All other faces. */
2838  BMLoop *l_radial_iter = l_iter;
2839  do {
2840  int i_other = BM_elem_index_get(l_radial_iter->f);
2841  if (!ELEM(i_other, -1, i)) {
2842  float angle = angle_normalized_v3v3(f->no, l_radial_iter->f->no);
2843  /* Ignore face direction since in the case on non-manifold faces connecting edges,
2844  * the face flipping may not be meaningful. */
2845  if (angle > DEG2RADF(90)) {
2846  angle = DEG2RADF(180) - angle;
2847  }
2848  /* Avoid calculating it inline, pass in pre-calculated edge lengths. */
2849 #if 0
2850  cost_test += BM_edge_calc_length(l_iter->e) * angle;
2851 #else
2852  BLI_assert(edge_lengths[BM_elem_index_get(l_iter->e)] != -1.0f);
2853  cost_test += edge_lengths[BM_elem_index_get(l_iter->e)] * angle;
2854 #endif
2855  cost_count += 1;
2856  }
2857  } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
2858 
2859  if (cost_count >= 2) {
2860  cost += cost_test;
2861  found = true;
2862  }
2863  }
2864  } while ((l_iter = l_iter->next) != l_first);
2865  }
2866  return found ? cost / area : FLT_MAX;
2867 }
2868 
2870 {
2871  BMesh *bm = em->bm;
2872  BMIter iter;
2873  bool changed = false;
2874 
2875  float *edge_lengths = MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__);
2876 
2877  {
2878  bool has_nonmanifold = false;
2879  BMEdge *e;
2880  int i;
2881  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
2882  const bool is_over = BM_edge_face_count_is_over(e, 2);
2883  if (is_over) {
2885  has_nonmanifold = true;
2886  edge_lengths[i] = BM_edge_calc_length(e);
2887  }
2888  else {
2890  edge_lengths[i] = -1.0;
2891  }
2892 
2893  BM_elem_index_set(e, i); /* set_inline */
2894  }
2896 
2897  if (has_nonmanifold == false) {
2898  MEM_freeN(edge_lengths);
2899  return false;
2900  }
2901  }
2902 
2903  /* group vars */
2904  int *fgroup_array;
2905  int(*fgroup_index)[2];
2906  int fgroup_len;
2907 
2908  fgroup_array = MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__);
2909  fgroup_len = BM_mesh_calc_face_groups(
2910  bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, NULL, NULL, 0, BM_EDGE);
2911 
2912  int *fgroup_recalc_stack = MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__);
2913  STACK_DECLARE(fgroup_recalc_stack);
2914  STACK_INIT(fgroup_recalc_stack, fgroup_len);
2915 
2917 
2918  {
2919  BMFace *f;
2920  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2921  BM_elem_index_set(f, -1); /* set_dirty! */
2922  }
2923  }
2925 
2926  ListBase *fgroup_listbase = MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__);
2927  struct BMFaceLink *f_link_array = MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__);
2928 
2929  for (int i = 0; i < fgroup_len; i++) {
2930  const int fg_sta = fgroup_index[i][0];
2931  const int fg_len = fgroup_index[i][1];
2932  for (int j = 0; j < fg_len; j++) {
2933  const int face_index = fgroup_array[fg_sta + j];
2934  BMFace *f = BM_face_at_index(bm, face_index);
2935  BM_elem_index_set(f, i);
2936 
2937  struct BMFaceLink *f_link = &f_link_array[face_index];
2938  f_link->face = f;
2939  f_link->area = BM_face_calc_area(f);
2940  BLI_addtail(&fgroup_listbase[i], f_link);
2941  }
2942  }
2943 
2944  MEM_freeN(fgroup_array);
2945  MEM_freeN(fgroup_index);
2946 
2947  Heap *fgroup_heap = BLI_heap_new_ex(fgroup_len);
2948  HeapNode **fgroup_table = MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__);
2949  bool *fgroup_dirty = MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__);
2950 
2951  for (int i = 0; i < fgroup_len; i++) {
2952  const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
2953  if (cost != FLT_MAX) {
2954  fgroup_table[i] = BLI_heap_insert(fgroup_heap, -cost, POINTER_FROM_INT(i));
2955  }
2956  else {
2957  fgroup_table[i] = NULL;
2958  }
2959  }
2960 
2961  /* Avoid re-running cost calculations for large face-groups which will end up forming the
2962  * outer shell and not be considered interior.
2963  * As these face groups become increasingly bigger - their chance of being considered
2964  * interior reduces as does the time to calculate their cost.
2965  *
2966  * This delays recalculating them until they are considered can dates to remove
2967  * which becomes less and less likely as they increase in area. */
2968 
2969 #define USE_DELAY_FACE_GROUP_COST_CALC
2970 
2971  while (true) {
2972 
2973 #if defined(USE_DELAY_FACE_GROUP_COST_CALC)
2974  while (!BLI_heap_is_empty(fgroup_heap)) {
2975  HeapNode *node_min = BLI_heap_top(fgroup_heap);
2976  const int i = POINTER_AS_INT(BLI_heap_node_ptr(node_min));
2977  if (fgroup_dirty[i]) {
2978  const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
2979  if (cost != FLT_MAX) {
2980  /* The cost may have improves (we may be able to skip this),
2981  * however the cost should _never_ make this a choice. */
2982  BLI_assert(-BLI_heap_node_value(node_min) >= cost);
2983  BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
2984  }
2985  else {
2986  BLI_heap_remove(fgroup_heap, fgroup_table[i]);
2987  fgroup_table[i] = NULL;
2988  }
2989  fgroup_dirty[i] = false;
2990  }
2991  else {
2992  break;
2993  }
2994  }
2995 #endif
2996 
2997  if (BLI_heap_is_empty(fgroup_heap)) {
2998  break;
2999  }
3000 
3001  const int i_min = POINTER_AS_INT(BLI_heap_pop_min(fgroup_heap));
3002  BLI_assert(fgroup_table[i_min] != NULL);
3003  BLI_assert(fgroup_dirty[i_min] == false);
3004  fgroup_table[i_min] = NULL;
3005  changed = true;
3006 
3007  struct BMFaceLink *f_link;
3008  while ((f_link = BLI_pophead(&fgroup_listbase[i_min]))) {
3009  BMFace *f = f_link->face;
3010  BM_face_select_set(bm, f, true);
3011  BM_elem_index_set(f, -1); /* set-dirty */
3012 
3013  BMLoop *l_iter, *l_first;
3014 
3015  /* Loop over edges face edges, merging groups which are no longer separated
3016  * by non-manifold edges (when manifold check ignores faces from this group). */
3017  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
3018  do {
3019  BMLoop *l_pair[2];
3020  if (bm_interior_edge_is_manifold_except_face_index(l_iter->e, i_min, l_pair)) {
3022 
3023  int i_a = BM_elem_index_get(l_pair[0]->f);
3024  int i_b = BM_elem_index_get(l_pair[1]->f);
3025  if (i_a != i_b) {
3026  /* Only for predictable results that don't depend on the order of radial loops,
3027  * not essential. */
3028  if (i_a > i_b) {
3029  SWAP(int, i_a, i_b);
3030  }
3031 
3032  /* Merge the groups. */
3033  LISTBASE_FOREACH (LinkData *, n, &fgroup_listbase[i_b]) {
3034  BMFace *f_iter = n->data;
3035  BM_elem_index_set(f_iter, i_a);
3036  }
3037  BLI_movelisttolist(&fgroup_listbase[i_a], &fgroup_listbase[i_b]);
3038 
3039  /* This may have been added to 'fgroup_recalc_stack', instead of removing it,
3040  * just check the heap node isn't NULL before recalculating. */
3041  BLI_heap_remove(fgroup_heap, fgroup_table[i_b]);
3042  fgroup_table[i_b] = NULL;
3043  /* Keep the dirty flag as-is for 'i_b', because it may be in the 'fgroup_recalc_stack'
3044  * and we don't want to add it again.
3045  * Instead rely on the 'fgroup_table[i_b]' being NULL as a secondary check. */
3046 
3047  if (fgroup_dirty[i_a] == false) {
3048  BLI_assert(fgroup_table[i_a] != NULL);
3049  STACK_PUSH(fgroup_recalc_stack, i_a);
3050  fgroup_dirty[i_a] = true;
3051  }
3052  }
3053  }
3054 
3055  /* Mark all connected groups for re-calculation. */
3056  BMLoop *l_radial_iter = l_iter->radial_next;
3057  if (l_radial_iter != l_iter) {
3058  do {
3059  int i_other = BM_elem_index_get(l_radial_iter->f);
3060  if (!ELEM(i_other, -1, i_min)) {
3061  if ((fgroup_table[i_other] != NULL) && (fgroup_dirty[i_other] == false)) {
3062 #if !defined(USE_DELAY_FACE_GROUP_COST_CALC)
3063  STACK_PUSH(fgroup_recalc_stack, i_other);
3064 #endif
3065  fgroup_dirty[i_other] = true;
3066  }
3067  }
3068  } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
3069  }
3070 
3071  } while ((l_iter = l_iter->next) != l_first);
3072  }
3073 
3074  for (int index = 0; index < STACK_SIZE(fgroup_recalc_stack); index++) {
3075  const int i = fgroup_recalc_stack[index];
3076  if (fgroup_table[i] != NULL && fgroup_dirty[i] == true) {
3077  /* First update edge tags. */
3078  const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
3079  if (cost != FLT_MAX) {
3080  BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
3081  }
3082  else {
3083  BLI_heap_remove(fgroup_heap, fgroup_table[i]);
3084  fgroup_table[i] = NULL;
3085  }
3086  }
3087  fgroup_dirty[i] = false;
3088  }
3089  STACK_CLEAR(fgroup_recalc_stack);
3090  }
3091 
3092  MEM_freeN(edge_lengths);
3093  MEM_freeN(f_link_array);
3094  MEM_freeN(fgroup_listbase);
3095  MEM_freeN(fgroup_recalc_stack);
3096  MEM_freeN(fgroup_table);
3097  MEM_freeN(fgroup_dirty);
3098 
3099  BLI_heap_free(fgroup_heap, NULL);
3100 
3101  return changed;
3102 }
3103 
3106 /* -------------------------------------------------------------------- */
3112 /* so we can have last-used default depend on selection mode (rare exception!) */
3113 #define USE_LINKED_SELECT_DEFAULT_HACK
3114 
3115 struct DelimitData {
3116  int cd_loop_type;
3117  int cd_loop_offset;
3118 };
3119 
3121  int delimit,
3122  const struct DelimitData *delimit_data)
3123 {
3124  BLI_assert(delimit);
3125 
3126  if (delimit & BMO_DELIM_SEAM) {
3128  return true;
3129  }
3130  }
3131 
3132  if (delimit & BMO_DELIM_SHARP) {
3133  if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
3134  return true;
3135  }
3136  }
3137 
3138  if (delimit & BMO_DELIM_NORMAL) {
3139  if (!BM_edge_is_contiguous(e)) {
3140  return true;
3141  }
3142  }
3143 
3144  if (delimit & BMO_DELIM_MATERIAL) {
3145  if (e->l && e->l->radial_next != e->l) {
3146  const short mat_nr = e->l->f->mat_nr;
3147  BMLoop *l_iter = e->l->radial_next;
3148  do {
3149  if (l_iter->f->mat_nr != mat_nr) {
3150  return true;
3151  }
3152  } while ((l_iter = l_iter->radial_next) != e->l);
3153  }
3154  }
3155 
3156  if (delimit & BMO_DELIM_UV) {
3158  e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) {
3159  return true;
3160  }
3161  }
3162 
3163  return false;
3164 }
3165 
3166 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3171 static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode)
3172 {
3173  static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
3174  int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
3175  char *delimit_last = &delimit_last_store[delimit_last_index];
3176  PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit");
3177  int delimit;
3178 
3179  if (RNA_property_is_set(op->ptr, prop_delimit)) {
3180  delimit = RNA_property_enum_get(op->ptr, prop_delimit);
3181  *delimit_last = delimit;
3182  }
3183  else {
3184  delimit = *delimit_last;
3185  RNA_property_enum_set(op->ptr, prop_delimit, delimit);
3186  }
3187  return delimit;
3188 }
3189 #endif
3190 
3191 static void select_linked_delimit_validate(BMesh *bm, int *delimit)
3192 {
3193  if ((*delimit) & BMO_DELIM_UV) {
3195  (*delimit) &= ~BMO_DELIM_UV;
3196  }
3197  }
3198 }
3199 
3200 static void select_linked_delimit_begin(BMesh *bm, int delimit)
3201 {
3202  struct DelimitData delimit_data = {0};
3203 
3204  if (delimit & BMO_DELIM_UV) {
3205  delimit_data.cd_loop_type = CD_MLOOPUV;
3206  delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
3207  if (delimit_data.cd_loop_offset == -1) {
3208  delimit &= ~BMO_DELIM_UV;
3209  }
3210  }
3211 
3212  /* grr, shouldn't need to alloc BMO flags here */
3214 
3215  {
3216  BMIter iter;
3217  BMEdge *e;
3218 
3219  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
3220  const bool is_walk_ok = ((select_linked_delimit_test(e, delimit, &delimit_data) == false));
3221 
3222  BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
3223  }
3224  }
3225 }
3226 
3228 {
3229  BMesh *bm = em->bm;
3230 
3232 }
3233 
3235 {
3237  ViewLayer *view_layer = CTX_data_view_layer(C);
3238 
3239 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3240  const int delimit_init = select_linked_delimit_default_from_op(op,
3242 #else
3243  const int delimit_init = RNA_enum_get(op->ptr, "delimit");
3244 #endif
3245 
3246  uint objects_len = 0;
3248  view_layer, CTX_wm_view3d(C), &objects_len);
3249 
3250  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3251  Object *obedit = objects[ob_index];
3252 
3253  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3254  BMesh *bm = em->bm;
3255  BMIter iter;
3256  BMWalker walker;
3257 
3258  int delimit = delimit_init;
3259 
3261 
3262  if (delimit) {
3263  select_linked_delimit_begin(em->bm, delimit);
3264  }
3265 
3266  if (em->selectmode & SCE_SELECT_VERTEX) {
3267  BMVert *v;
3268 
3269  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3271  }
3272 
3273  /* exclude all delimited verts */
3274  if (delimit) {
3275  BMEdge *e;
3276  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3277  if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
3278  /* Check the edge for selected faces,
3279  * this supports stepping off isolated vertices which would otherwise be ignored. */
3283  }
3284  }
3285  }
3286  }
3287 
3288  BMW_init(&walker,
3289  em->bm,
3290  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3291  BMW_MASK_NOP,
3292  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3293  BMW_MASK_NOP,
3295  BMW_NIL_LAY);
3296 
3297  if (delimit) {
3298  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3300  BMElem *ele_walk;
3301  BMW_ITER (ele_walk, &walker, v) {
3302  if (ele_walk->head.htype == BM_LOOP) {
3303  BMVert *v_step = ((BMLoop *)ele_walk)->v;
3304  BM_vert_select_set(em->bm, v_step, true);
3306  }
3307  else {
3308  BMEdge *e_step = (BMEdge *)ele_walk;
3309  BLI_assert(ele_walk->head.htype == BM_EDGE);
3310  BM_edge_select_set(em->bm, e_step, true);
3313  }
3314  }
3315  }
3316  }
3317  }
3318  else {
3319  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
3321  BMEdge *e_walk;
3322  BMW_ITER (e_walk, &walker, v) {
3323  BM_edge_select_set(em->bm, e_walk, true);
3325  }
3326  }
3327  }
3328  }
3329 
3330  BMW_end(&walker);
3331 
3333  }
3334  else if (em->selectmode & SCE_SELECT_EDGE) {
3335  BMEdge *e;
3336 
3337  if (delimit) {
3338  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3339  /* Check the edge for selected faces,
3340  * this supports stepping off isolated edges which would otherwise be ignored. */
3342  BM_ELEM_TAG,
3346  }
3347  }
3348  else {
3349  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3351  }
3352  }
3353 
3354  BMW_init(&walker,
3355  em->bm,
3356  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3357  BMW_MASK_NOP,
3358  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3359  BMW_MASK_NOP,
3361  BMW_NIL_LAY);
3362 
3363  if (delimit) {
3364  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3366  BMElem *ele_walk;
3367  BMW_ITER (ele_walk, &walker, e) {
3368  if (ele_walk->head.htype == BM_LOOP) {
3369  BMLoop *l_step = (BMLoop *)ele_walk;
3370  BM_edge_select_set(em->bm, l_step->e, true);
3371  BM_edge_select_set(em->bm, l_step->prev->e, true);
3373  }
3374  else {
3375  BMEdge *e_step = (BMEdge *)ele_walk;
3376  BLI_assert(ele_walk->head.htype == BM_EDGE);
3377  BM_edge_select_set(em->bm, e_step, true);
3379  }
3380  }
3381  }
3382  }
3383  }
3384  else {
3385  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
3387  BMEdge *e_walk;
3388  BMW_ITER (e_walk, &walker, e) {
3389  BM_edge_select_set(em->bm, e_walk, true);
3391  }
3392  }
3393  }
3394  }
3395 
3396  BMW_end(&walker);
3397 
3399  }
3400  else {
3401  BMFace *f;
3402 
3403  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
3405  }
3406 
3407  BMW_init(&walker,
3408  bm,
3409  BMW_ISLAND,
3410  BMW_MASK_NOP,
3411  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3412  BMW_MASK_NOP,
3414  BMW_NIL_LAY);
3415 
3416  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
3417  if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
3418  BMFace *f_walk;
3419  BMW_ITER (f_walk, &walker, f) {
3420  BM_face_select_set(bm, f_walk, true);
3422  }
3423  }
3424  }
3425 
3426  BMW_end(&walker);
3427  }
3428 
3429  if (delimit) {
3431  }
3432 
3435  }
3436 
3437  MEM_freeN(objects);
3438 
3439  return OPERATOR_FINISHED;
3440 }
3441 
3443 {
3444  PropertyRNA *prop;
3445 
3446  /* identifiers */
3447  ot->name = "Select Linked All";
3448  ot->idname = "MESH_OT_select_linked";
3449  ot->description = "Select all vertices connected to the current selection";
3450 
3451  /* api callbacks */
3454 
3455  /* flags */
3457 
3458  prop = RNA_def_enum_flag(ot->srna,
3459  "delimit",
3462  "Delimit",
3463  "Delimit selected region");
3464 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3466 #else
3467  UNUSED_VARS(prop);
3468 #endif
3469 }
3470 
3473 /* -------------------------------------------------------------------- */
3478 
3479 static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
3480 {
3481  BMesh *bm = em->bm;
3482  BMWalker walker;
3483 
3485 
3486  if (delimit) {
3487  select_linked_delimit_begin(bm, delimit);
3488  }
3489 
3490  /* NOTE: logic closely matches #edbm_select_linked_exec, keep in sync. */
3491 
3492  if (ele->head.htype == BM_VERT) {
3493  BMVert *eve = (BMVert *)ele;
3494 
3495  BMW_init(&walker,
3496  bm,
3497  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3498  BMW_MASK_NOP,
3499  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3500  BMW_MASK_NOP,
3502  BMW_NIL_LAY);
3503 
3504  if (delimit) {
3505  BMElem *ele_walk;
3506  BMW_ITER (ele_walk, &walker, eve) {
3507  if (ele_walk->head.htype == BM_LOOP) {
3508  BMVert *v_step = ((BMLoop *)ele_walk)->v;
3509  BM_vert_select_set(bm, v_step, sel);
3510  }
3511  else {
3512  BMEdge *e_step = (BMEdge *)ele_walk;
3513  BLI_assert(ele_walk->head.htype == BM_EDGE);
3514  BM_edge_select_set(bm, e_step, sel);
3515  }
3516  }
3517  }
3518  else {
3519  BMEdge *e_walk;
3520  BMW_ITER (e_walk, &walker, eve) {
3521  BM_edge_select_set(bm, e_walk, sel);
3522  }
3523  }
3524 
3525  BMW_end(&walker);
3526 
3528  }
3529  else if (ele->head.htype == BM_EDGE) {
3530  BMEdge *eed = (BMEdge *)ele;
3531 
3532  BMW_init(&walker,
3533  bm,
3534  delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3535  BMW_MASK_NOP,
3536  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3537  BMW_MASK_NOP,
3539  BMW_NIL_LAY);
3540 
3541  if (delimit) {
3542  BMElem *ele_walk;
3543  BMW_ITER (ele_walk, &walker, eed) {
3544  if (ele_walk->head.htype == BM_LOOP) {
3545  BMEdge *e_step = ((BMLoop *)ele_walk)->e;
3546  BM_edge_select_set(bm, e_step, sel);
3547  }
3548  else {
3549  BMEdge *e_step = (BMEdge *)ele_walk;
3550  BLI_assert(ele_walk->head.htype == BM_EDGE);
3551  BM_edge_select_set(bm, e_step, sel);
3552  }
3553  }
3554  }
3555  else {
3556  BMEdge *e_walk;
3557  BMW_ITER (e_walk, &walker, eed) {
3558  BM_edge_select_set(bm, e_walk, sel);
3559  }
3560  }
3561 
3562  BMW_end(&walker);
3563 
3565  }
3566  else if (ele->head.htype == BM_FACE) {
3567  BMFace *efa = (BMFace *)ele;
3568 
3569  BMW_init(&walker,
3570  bm,
3571  BMW_ISLAND,
3572  BMW_MASK_NOP,
3573  delimit ? BMO_ELE_TAG : BMW_MASK_NOP,
3574  BMW_MASK_NOP,
3576  BMW_NIL_LAY);
3577 
3578  {
3579  BMFace *f_walk;
3580  BMW_ITER (f_walk, &walker, efa) {
3581  BM_face_select_set(bm, f_walk, sel);
3583  }
3584  }
3585 
3586  BMW_end(&walker);
3587  }
3588 
3589  if (delimit) {
3591  }
3592 }
3593 
3595 {
3596  ViewContext vc;
3597  Base *basact = NULL;
3598  BMVert *eve;
3599  BMEdge *eed;
3600  BMFace *efa;
3601  const bool sel = !RNA_boolean_get(op->ptr, "deselect");
3602  int index;
3603 
3604  if (RNA_struct_property_is_set(op->ptr, "index")) {
3605  return edbm_select_linked_pick_exec(C, op);
3606  }
3607 
3608  /* #unified_findnearest needs OpenGL. */
3610 
3611  /* setup view context for argument to callbacks */
3612  em_setup_viewcontext(C, &vc);
3613 
3614  uint bases_len;
3615  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
3616 
3617  {
3618  bool has_edges = false;
3619  for (uint base_index = 0; base_index < bases_len; base_index++) {
3620  Object *ob_iter = bases[base_index]->object;
3621  ED_view3d_viewcontext_init_object(&vc, ob_iter);
3622  if (vc.em->bm->totedge) {
3623  has_edges = true;
3624  }
3625  }
3626  if (has_edges == false) {
3627  MEM_freeN(bases);
3628  return OPERATOR_CANCELLED;
3629  }
3630  }
3631 
3632  vc.mval[0] = event->mval[0];
3633  vc.mval[1] = event->mval[1];
3634 
3635  /* return warning! */
3636  {
3637  int base_index = -1;
3638  const bool ok = unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa);
3639  if (!ok) {
3640  MEM_freeN(bases);
3641  return OPERATOR_CANCELLED;
3642  }
3643  basact = bases[base_index];
3644  }
3645 
3647  BMEditMesh *em = vc.em;
3648  BMesh *bm = em->bm;
3649 
3650 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3652 #else
3653  int delimit = RNA_enum_get(op->ptr, "delimit");
3654 #endif
3655 
3656  BMElem *ele = EDBM_elem_from_selectmode(em, eve, eed, efa);
3657 
3658  edbm_select_linked_pick_ex(em, ele, sel, delimit);
3659 
3660  /* To support redo. */
3661  {
3662  /* Note that the `base_index` can't be used as the index depends on the 3D Viewport
3663  * which might not be available on redo. */
3665  int object_index;
3666  index = EDBM_elem_to_index_any_multi(vc.view_layer, em, ele, &object_index);
3667  BLI_assert(object_index >= 0);
3668  RNA_int_set(op->ptr, "object_index", object_index);
3669  RNA_int_set(op->ptr, "index", index);
3670  }
3671 
3674 
3675  MEM_freeN(bases);
3676  return OPERATOR_FINISHED;
3677 }
3678 
3680 {
3681  Object *obedit = NULL;
3682  BMElem *ele;
3683 
3684  {
3685  ViewLayer *view_layer = CTX_data_view_layer(C);
3686  /* Intentionally wrap negative values so the lookup fails. */
3687  const uint object_index = (uint)RNA_int_get(op->ptr, "object_index");
3688  const uint index = (uint)RNA_int_get(op->ptr, "index");
3689  ele = EDBM_elem_from_index_any_multi(view_layer, object_index, index, &obedit);
3690  }
3691 
3692  if (ele == NULL) {
3693  return OPERATOR_CANCELLED;
3694  }
3695 
3696  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3697  const bool sel = !RNA_boolean_get(op->ptr, "deselect");
3698 
3699 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3700  int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
3701 #else
3702  int delimit = RNA_enum_get(op->ptr, "delimit");
3703 #endif
3704 
3705  edbm_select_linked_pick_ex(em, ele, sel, delimit);
3706 
3709 
3710  return OPERATOR_FINISHED;
3711 }
3712 
3714 {
3715  PropertyRNA *prop;
3716 
3717  /* identifiers */
3718  ot->name = "Select Linked";
3719  ot->idname = "MESH_OT_select_linked_pick";
3720  ot->description = "(De)select all vertices linked to the edge under the mouse cursor";
3721 
3722  /* api callbacks */
3726 
3727  /* flags */
3729 
3730  RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
3731  prop = RNA_def_enum_flag(ot->srna,
3732  "delimit",
3735  "Delimit",
3736  "Delimit selected region");
3737 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3739 #endif
3740 
3741  /* use for redo */
3742  prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
3744  prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
3746 }
3747 
3750 /* -------------------------------------------------------------------- */
3755 {
3756  ViewLayer *view_layer = CTX_data_view_layer(C);
3757  uint objects_len = 0;
3758  const bool extend = RNA_boolean_get(op->ptr, "extend");
3759  const int numverts = RNA_int_get(op->ptr, "number");
3760  const int type = RNA_enum_get(op->ptr, "type");
3762  view_layer, CTX_wm_view3d(C), &objects_len);
3763 
3764  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3765  Object *obedit = objects[ob_index];
3766  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3767  BMFace *efa;
3768  BMIter iter;
3769 
3770  if (!extend) {
3772  }
3773 
3774  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3775  bool select;
3776 
3777  switch (type) {
3778  case 0:
3779  select = (efa->len < numverts);
3780  break;
3781  case 1:
3782  select = (efa->len == numverts);
3783  break;
3784  case 2:
3785  select = (efa->len > numverts);
3786  break;
3787  case 3:
3788  select = (efa->len != numverts);
3789  break;
3790  default:
3791  BLI_assert(0);
3792  select = false;
3793  break;
3794  }
3795 
3796  if (select) {
3797  BM_face_select_set(em->bm, efa, true);
3798  }
3799  }
3800 
3802 
3805  }
3806 
3807  MEM_freeN(objects);
3808  return OPERATOR_FINISHED;
3809 }
3810 
3812 {
3813  static const EnumPropertyItem type_items[] = {
3814  {0, "LESS", 0, "Less Than", ""},
3815  {1, "EQUAL", 0, "Equal To", ""},
3816  {2, "GREATER", 0, "Greater Than", ""},
3817  {3, "NOTEQUAL", 0, "Not Equal To", ""},
3818  {0, NULL, 0, NULL, NULL},
3819  };
3820 
3821  /* identifiers */
3822  ot->name = "Select Faces by Sides";
3823  ot->description = "Select vertices or faces by the number of polygon sides";
3824  ot->idname = "MESH_OT_select_face_by_sides";
3825 
3826  /* api callbacks */
3829 
3830  /* flags */
3832 
3833  /* properties */
3834  RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX);
3835  RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make");
3836  RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
3837 }
3838 
3841 /* -------------------------------------------------------------------- */
3846 {
3847  ViewLayer *view_layer = CTX_data_view_layer(C);
3848  const bool extend = RNA_boolean_get(op->ptr, "extend");
3849 
3850  uint objects_len = 0;
3852  view_layer, CTX_wm_view3d(C), &objects_len);
3853 
3854  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3855  Object *obedit = objects[ob_index];
3856  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3857  BMesh *bm = em->bm;
3858  BMIter iter;
3859 
3860  if (!extend) {
3862  }
3863 
3864  if (em->selectmode & SCE_SELECT_VERTEX) {
3865  BMVert *eve;
3866  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
3867  if (!eve->e) {
3868  BM_vert_select_set(bm, eve, true);
3869  }
3870  }
3871  }
3872 
3873  if (em->selectmode & SCE_SELECT_EDGE) {
3874  BMEdge *eed;
3875  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
3876  if (BM_edge_is_wire(eed)) {
3877  BM_edge_select_set(bm, eed, true);
3878  }
3879  }
3880  }
3881 
3882  if (em->selectmode & SCE_SELECT_FACE) {
3883  BMFace *efa;
3884  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
3885  BMIter liter;
3886  BMLoop *l;
3887  bool is_loose = true;
3888  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3889  if (!BM_edge_is_boundary(l->e)) {
3890  is_loose = false;
3891  break;
3892  }
3893  }
3894  if (is_loose) {
3895  BM_face_select_set(bm, efa, true);
3896  }
3897  }
3898  }
3899 
3901 
3904  }
3905 
3906  MEM_freeN(objects);
3907 
3908  return OPERATOR_FINISHED;
3909 }
3910 
3912 {
3913  /* identifiers */
3914  ot->name = "Select Loose Geometry";
3915  ot->description = "Select loose geometry based on the selection mode";
3916  ot->idname = "MESH_OT_select_loose";
3917 
3918  /* api callbacks */
3921 
3922  /* flags */
3924 
3925  /* props */
3926  RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
3927 }
3928 
3931 /* -------------------------------------------------------------------- */
3936 {
3937  ViewLayer *view_layer = CTX_data_view_layer(C);
3938  const int axis_flag = RNA_enum_get(op->ptr, "axis");
3939  const bool extend = RNA_boolean_get(op->ptr, "extend");
3940  Object *obedit_active = CTX_data_edit_object(C);
3941  BMEditMesh *em_active = BKE_editmesh_from_object(obedit_active);
3942  const int select_mode = em_active->bm->selectmode;
3943  int tot_mirr = 0, tot_fail = 0;
3944 
3945  uint objects_len = 0;
3947  view_layer, CTX_wm_view3d(C), &objects_len);
3948 
3949  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3950  Object *obedit = objects[ob_index];
3951  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3952 
3953  if (em->bm->totvertsel == 0) {
3954  continue;
3955  }
3956 
3957  int tot_mirr_iter = 0, tot_fail_iter = 0;
3958 
3959  for (int axis = 0; axis < 3; axis++) {
3960  if ((1 << axis) & axis_flag) {
3961  EDBM_select_mirrored(em, obedit->data, axis, extend, &tot_mirr_iter, &tot_fail_iter);
3962  }
3963  }
3964 
3965  if (tot_mirr_iter) {
3967 
3970  }
3971 
3972  tot_fail += tot_fail_iter;
3973  tot_mirr += tot_mirr_iter;
3974  }
3975  MEM_freeN(objects);
3976 
3977  if (tot_mirr || tot_fail) {
3978  ED_mesh_report_mirror_ex(op, tot_mirr, tot_fail, select_mode);
3979  }
3980  return OPERATOR_FINISHED;
3981 }
3982 
3984 {
3985  /* identifiers */
3986  ot->name = "Select Mirror";
3987  ot->description = "Select mesh items at mirrored locations";
3988  ot->idname = "MESH_OT_select_mirror";
3989 
3990  /* api callbacks */
3993 
3994  /* flags */
3996 
3997  /* props */
3998  RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", "");
3999 
4000  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
4001 }
4002 
4005 /* -------------------------------------------------------------------- */
4010 {
4011  ViewLayer *view_layer = CTX_data_view_layer(C);
4012  const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
4013 
4014  uint objects_len = 0;
4016  view_layer, CTX_wm_view3d(C), &objects_len);
4017  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4018  Object *obedit = objects[ob_index];
4019  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4020  BMesh *bm = em->bm;
4021 
4022  if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) {
4023  continue;
4024  }
4025 
4026  EDBM_select_more(em, use_face_step);
4029  }
4030 
4031  MEM_freeN(objects);
4032  return OPERATOR_FINISHED;
4033 }
4034 
4036 {
4037  /* identifiers */
4038  ot->name = "Select More";
4039  ot->idname = "MESH_OT_select_more";
4040  ot->description = "Select more vertices, edges or faces connected to initial selection";
4041 
4042  /* api callbacks */
4045 
4046  /* flags */
4048 
4050  ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
4051 }
4052 
4055 /* -------------------------------------------------------------------- */
4060 {
4061  ViewLayer *view_layer = CTX_data_view_layer(C);
4062  const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
4063 
4064  uint objects_len = 0;
4066  view_layer, CTX_wm_view3d(C), &objects_len);
4067  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4068  Object *obedit = objects[ob_index];
4069  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4070  BMesh *bm = em->bm;
4071 
4072  if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) {
4073  continue;
4074  }
4075 
4076  EDBM_select_less(em, use_face_step);
4079  }
4080 
4081  MEM_freeN(objects);
4082  return OPERATOR_FINISHED;
4083 }
4084 
4086 {
4087  /* identifiers */
4088  ot->name = "Select Less";
4089  ot->idname = "MESH_OT_select_less";
4090  ot->description = "Deselect vertices, edges or faces at the boundary of each selection region";
4091 
4092  /* api callbacks */
4095 
4096  /* flags */
4098 
4100  ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
4101 }
4102 
4105 /* -------------------------------------------------------------------- */
4113 {
4114  BMIter viter;
4115  BMVert *v;
4116 
4117  BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
4118  BMIter eiter;
4119  BMEdge *e_other;
4120 
4121  BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) {
4122  if ((e_other != e) && BM_elem_flag_test(e_other, BM_ELEM_SELECT)) {
4123  return false;
4124  }
4125  }
4126  }
4127  return true;
4128 }
4129 
4130 /* Walk all reachable elements of the same type as h_act in breadth-first
4131  * order, starting from h_act. Deselects elements if the depth when they
4132  * are reached is not a multiple of "nth". */
4134  const struct CheckerIntervalParams *op_params,
4135  BMHeader *h_act)
4136 {
4137  BMElem *ele;
4138  BMesh *bm = em->bm;
4139  BMWalker walker;
4140  BMIter iter;
4141  int walktype = 0, itertype = 0, flushtype = 0;
4142  short mask_vert = 0, mask_edge = 0, mask_face = 0;
4143 
4144  /* No active element from which to start - nothing to do */
4145  if (h_act == NULL) {
4146  return;
4147  }
4148 
4149  /* Determine which type of iter, walker, and select flush to use
4150  * based on type of the elements being deselected */
4151  switch (h_act->htype) {
4152  case BM_VERT:
4153  itertype = BM_VERTS_OF_MESH;
4154  walktype = BMW_CONNECTED_VERTEX;
4155  flushtype = SCE_SELECT_VERTEX;
4156  mask_vert = BMO_ELE_TAG;
4157  break;
4158  case BM_EDGE:
4159  /* When an edge has no connected-selected edges,
4160  * use face-stepping (supports edge-rings) */
4161  itertype = BM_EDGES_OF_MESH;
4163  flushtype = SCE_SELECT_EDGE;
4164  mask_edge = BMO_ELE_TAG;
4165  break;
4166  case BM_FACE:
4167  itertype = BM_FACES_OF_MESH;
4168  walktype = BMW_ISLAND;
4169  flushtype = SCE_SELECT_FACE;
4170  mask_face = BMO_ELE_TAG;
4171  break;
4172  }
4173 
4174  /* grr, shouldn't need to alloc BMO flags here */
4176 
4177  /* Walker restrictions uses BMO flags, not header flags,
4178  * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */
4179  BMO_push(bm, NULL);
4180  BM_ITER_MESH (ele, &iter, bm, itertype) {
4181  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
4183  }
4184  }
4185 
4186  /* Walk over selected elements starting at active */
4187  BMW_init(&walker,
4188  bm,
4189  walktype,
4190  mask_vert,
4191  mask_edge,
4192  mask_face,
4193  BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
4194  BMW_NIL_LAY);
4195 
4196  /* use tag to avoid touching the same verts twice */
4197  BM_ITER_MESH (ele, &iter, bm, itertype) {
4199  }
4200 
4201  BLI_assert(walker.order == BMW_BREADTH_FIRST);
4202  for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
4203  if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
4204  /* Deselect elements that aren't at "nth" depth from active */
4205  const int depth = BMW_current_depth(&walker) - 1;
4206  if (!WM_operator_properties_checker_interval_test(op_params, depth)) {
4207  BM_elem_select_set(bm, ele, false);
4208  }
4210  }
4211  }
4212  BMW_end(&walker);
4213 
4214  BMO_pop(bm);
4215 
4216  /* Flush selection up */
4217  EDBM_selectmode_flush_ex(em, flushtype);
4218 }
4219 
4220 static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
4221 {
4222  BMIter iter;
4223  BMElem *ele;
4224 
4225  *r_eve = NULL;
4226  *r_eed = NULL;
4227  *r_efa = NULL;
4228 
4230  ele = BM_mesh_active_elem_get(em->bm);
4231 
4232  if (ele && BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
4233  switch (ele->head.htype) {
4234  case BM_VERT:
4235  *r_eve = (BMVert *)ele;
4236  return;
4237  case BM_EDGE:
4238  *r_eed = (BMEdge *)ele;
4239  return;
4240  case BM_FACE:
4241  *r_efa = (BMFace *)ele;
4242  return;
4243  }
4244  }
4245 
4246  if (em->selectmode & SCE_SELECT_VERTEX) {
4247  BMVert *v;
4248  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
4250  *r_eve = v;
4251  return;
4252  }
4253  }
4254  }
4255  else if (em->selectmode & SCE_SELECT_EDGE) {
4256  BMEdge *e;
4257  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
4259  *r_eed = e;
4260  return;
4261  }
4262  }
4263  }
4264  else if (em->selectmode & SCE_SELECT_FACE) {
4265  BMFace *f = BM_mesh_active_face_get(em->bm, true, false);
4266  if (f && BM_elem_flag_test(f, BM_ELEM_SELECT)) {
4267  *r_efa = f;
4268  return;
4269  }
4270  }
4271 }
4272 
4273 static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params)
4274 {
4275  BMVert *v;
4276  BMEdge *e;
4277  BMFace *f;
4278 
4279  deselect_nth_active(em, &v, &e, &f);
4280 
4281  if (v) {
4282  walker_deselect_nth(em, op_params, &v->head);
4283  return true;
4284  }
4285  if (e) {
4286  walker_deselect_nth(em, op_params, &e->head);
4287  return true;
4288  }
4289  if (f) {
4290  walker_deselect_nth(em, op_params, &f->head);
4291  return true;
4292  }
4293 
4294  return false;
4295 }
4296 
4298 {
4299  ViewLayer *view_layer = CTX_data_view_layer(C);
4300  struct CheckerIntervalParams op_params;
4302  bool found_active_elt = false;
4303 
4304  uint objects_len = 0;
4306  view_layer, CTX_wm_view3d(C), &objects_len);
4307 
4308  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4309  Object *obedit = objects[ob_index];
4310  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4311 
4312  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
4313  continue;
4314  }
4315 
4316  if (edbm_deselect_nth(em, &op_params) == true) {
4317  found_active_elt = true;
4318  EDBM_update(obedit->data,
4319  &(const struct EDBMUpdate_Params){
4320  .calc_looptri = false,
4321  .calc_normals = false,
4322  .is_destructive = false,
4323  });
4324  }
4325  }
4326  MEM_freeN(objects);
4327 
4328  if (!found_active_elt) {
4329  BKE_report(op->reports, RPT_ERROR, "Mesh object(s) have no active vertex/edge/face");
4330  return OPERATOR_CANCELLED;
4331  }
4332 
4333  return OPERATOR_FINISHED;
4334 }
4335 
4337 {
4338  /* identifiers */
4339  ot->name = "Checker Deselect";
4340  ot->idname = "MESH_OT_select_nth";
4341  ot->description = "Deselect every Nth element starting from the active vertex, edge or face";
4342 
4343  /* api callbacks */
4346 
4347  /* flags */
4349 
4351 }
4352 
4354 {
4357 
4358  if (vc->obedit) {
4359  vc->em = BKE_editmesh_from_object(vc->obedit);
4360  }
4361 }
4362 
4365 /* -------------------------------------------------------------------- */
4370 {
4371  /* Find edges that have exactly two neighboring faces,
4372  * check the angle between those faces, and if angle is
4373  * small enough, select the edge
4374  */
4375  const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
4376 
4377  ViewLayer *view_layer = CTX_data_view_layer(C);
4378  uint objects_len = 0;
4380  view_layer, CTX_wm_view3d(C), &objects_len);
4381 
4382  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4383  Object *obedit = objects[ob_index];
4384  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4385  BMIter iter;
4386  BMEdge *e;
4387  BMLoop *l1, *l2;
4388 
4389  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
4390  if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false && BM_edge_loop_pair(e, &l1, &l2)) {
4391  /* edge has exactly two neighboring faces, check angle */
4392  const float angle_cos = dot_v3v3(l1->f->no, l2->f->no);
4393 
4394  if (angle_cos < angle_limit_cos) {
4395  BM_edge_select_set(em->bm, e, true);
4396  }
4397  }
4398  }
4399 
4400  if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
4401  /* Since we can't select individual edges, select faces connected to them. */
4403  }
4404  else {
4406  }
4409  }
4410  MEM_freeN(objects);
4411 
4412  return OPERATOR_FINISHED;
4413 }
4414 
4416 {
4417  PropertyRNA *prop;
4418 
4419  /* identifiers */
4420  ot->name = "Select Sharp Edges";
4421  ot->description = "Select all sharp enough edges";
4422  ot->idname = "MESH_OT_edges_select_sharp";
4423 
4424  /* api callbacks */
4427 
4428  /* flags */
4430 
4431  /* props */
4432  prop = RNA_def_float_rotation(ot->srna,
4433  "sharpness",
4434  0,
4435  NULL,
4436  DEG2RADF(0.01f),
4437  DEG2RADF(180.0f),
4438  "Sharpness",
4439  "",
4440  DEG2RADF(1.0f),
4441  DEG2RADF(180.0f));
4443 }
4444 
4447 /* -------------------------------------------------------------------- */
4452 {
4453  ViewLayer *view_layer = CTX_data_view_layer(C);
4454  uint objects_len = 0;
4456  view_layer, CTX_wm_view3d(C), &objects_len);
4457  const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
4458 
4459  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4460  Object *obedit = objects[ob_index];
4461  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4462  BMesh *bm = em->bm;
4463 
4464  if (bm->totfacesel == 0) {
4465  continue;
4466  }
4467 
4468  BLI_LINKSTACK_DECLARE(stack, BMFace *);
4469 
4470  BMIter iter, liter, liter2;
4471  BMFace *f;
4472  BMLoop *l, *l2;
4473 
4475 
4476  BLI_LINKSTACK_INIT(stack);
4477 
4478  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
4479  if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) ||
4480  (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) ||
4481  (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) {
4482  continue;
4483  }
4484 
4485  BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0);
4486 
4487  do {
4488  BM_face_select_set(bm, f, true);
4489 
4491 
4492  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
4493  BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
4494  float angle_cos;
4495 
4496  if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) ||
4498  continue;
4499  }
4500 
4501  angle_cos = dot_v3v3(f->no, l2->f->no);
4502 
4503  if (angle_cos > angle_limit_cos) {
4504  BLI_LINKSTACK_PUSH(stack, l2->f);
4505  }
4506  }
4507  }
4508  } while ((f = BLI_LINKSTACK_POP(stack)));
4509  }
4510 
4511  BLI_LINKSTACK_FREE(stack);
4512 
4515  }
4516  MEM_freeN(objects);
4517 
4518  return OPERATOR_FINISHED;
4519 }
4520 
4522 {
4523  PropertyRNA *prop;
4524 
4525  /* identifiers */
4526  ot->name = "Select Linked Flat Faces";
4527  ot->description = "Select linked faces by angle";
4528  ot->idname = "MESH_OT_faces_select_linked_flat";
4529 
4530  /* api callbacks */
4533 
4534  /* flags */
4536 
4537  /* props */
4538  prop = RNA_def_float_rotation(ot->srna,
4539  "sharpness",
4540  0,
4541  NULL,
4542  DEG2RADF(0.01f),
4543  DEG2RADF(180.0f),
4544  "Sharpness",
4545  "",
4546  DEG2RADF(1.0f),
4547  DEG2RADF(180.0f));
4549 }
4550 
4553 /* -------------------------------------------------------------------- */
4558 {
4559  const bool use_extend = RNA_boolean_get(op->ptr, "extend");
4560  const bool use_wire = RNA_boolean_get(op->ptr, "use_wire");
4561  const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
4562  const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face");
4563  const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous");
4564  const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
4565 
4566  ViewLayer *view_layer = CTX_data_view_layer(C);
4567  uint objects_len = 0;
4569  view_layer, CTX_wm_view3d(C), &objects_len);
4570 
4571  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4572  Object *obedit = objects[ob_index];
4573  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4574  BMVert *v;
4575  BMEdge *e;
4576  BMIter iter;
4577 
4578  if (!use_extend) {
4580  }
4581 
4582  /* Selects isolated verts, and edges that do not have 2 neighboring
4583  * faces
4584  */
4585 
4586  if (em->selectmode == SCE_SELECT_FACE) {
4587  BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
4588  MEM_freeN(objects);
4589  return OPERATOR_CANCELLED;
4590  }
4591 
4592  if (use_verts) {
4593  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
4595  if (!BM_vert_is_manifold(v)) {
4596  BM_vert_select_set(em->bm, v, true);
4597  }
4598  }
4599  }
4600  }
4601 
4602  if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
4603  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
4605  if ((use_wire && BM_edge_is_wire(e)) || (use_boundary && BM_edge_is_boundary(e)) ||
4606  (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
4607  (use_multi_face && (BM_edge_face_count_is_over(e, 2)))) {
4608  /* check we never select perfect edge (in test above) */
4610 
4611  BM_edge_select_set(em->bm, e, true);
4612  }
4613  }
4614  }
4615  }
4616 
4619 
4621  }
4622  MEM_freeN(objects);
4623 
4624  return OPERATOR_FINISHED;
4625 }
4626 
4628 {
4629  /* identifiers */
4630  ot->name = "Select Non-Manifold";
4631  ot->description = "Select all non-manifold vertices or edges";
4632  ot->idname = "MESH_OT_select_non_manifold";
4633 
4634  /* api callbacks */
4637 
4638  /* flags */
4640 
4641  /* props */
4642  RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
4643  /* edges */
4644  RNA_def_boolean(ot->srna, "use_wire", true, "Wire", "Wire edges");
4645  RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", "Boundary edges");
4647  ot->srna, "use_multi_face", true, "Multiple Faces", "Edges shared by more than two faces");
4649  "use_non_contiguous",
4650  true,
4651  "Non Contiguous",
4652  "Edges between faces pointing in alternate directions");
4653  /* verts */
4655  ot->srna, "use_verts", true, "Vertices", "Vertices connecting multiple face regions");
4656 }
4657 
4660 /* -------------------------------------------------------------------- */
4665 {
4666  const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
4667  const float randfac = RNA_float_get(op->ptr, "ratio");
4669 
4670  ViewLayer *view_layer = CTX_data_view_layer(C);
4671 
4672  uint objects_len = 0;
4674  view_layer, CTX_wm_view3d(C), &objects_len);
4675  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4676  Object *obedit = objects[ob_index];
4677  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4678  BMIter iter;
4679  int seed_iter = seed;
4680 
4681  /* This gives a consistent result regardless of object order. */
4682  if (ob_index) {
4683  seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
4684  }
4685 
4686  if (em->selectmode & SCE_SELECT_VERTEX) {
4687  int elem_map_len = 0;
4688  BMVert **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totvert, __func__);
4689  BMVert *eve;
4690  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
4691  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
4692  elem_map[elem_map_len++] = eve;
4693  }
4694  }
4695 
4696  BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter);
4697  const int count_select = elem_map_len * randfac;
4698  for (int i = 0; i < count_select; i++) {
4699  BM_vert_select_set(em->bm, elem_map[i], select);
4700  }
4701  MEM_freeN(elem_map);
4702  }
4703  else if (em->selectmode & SCE_SELECT_EDGE) {
4704  int elem_map_len = 0;
4705  BMEdge **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totedge, __func__);
4706  BMEdge *eed;
4707  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
4708  if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
4709  elem_map[elem_map_len++] = eed;
4710  }
4711  }
4712  BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter);
4713  const int count_select = elem_map_len * randfac;
4714  for (int i = 0; i < count_select; i++) {
4715  BM_edge_select_set(em->bm, elem_map[i], select);
4716  }
4717  MEM_freeN(elem_map);
4718  }
4719  else {
4720  int elem_map_len = 0;
4721  BMFace **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totface, __func__);
4722  BMFace *efa;
4723  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
4724  if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
4725  elem_map[elem_map_len++] = efa;
4726  }
4727  }
4728  BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter);
4729  const int count_select = elem_map_len * randfac;
4730  for (int i = 0; i < count_select; i++) {
4731  BM_face_select_set(em->bm, elem_map[i], select);
4732  }
4733  MEM_freeN(elem_map);
4734  }
4735 
4736  if (select) {
4737  /* was EDBM_select_flush, but it over select in edge/face mode */
4739  }
4740  else {
4741  EDBM_deselect_flush(em);
4742  }
4743 
4746  }
4747 
4748  MEM_freeN(objects);
4749  return OPERATOR_FINISHED;
4750 }
4751 
4753 {
4754  /* identifiers */
4755  ot->name = "Select Random";
4756  ot->description = "Randomly select vertices";
4757  ot->idname = "MESH_OT_select_random";
4758 
4759  /* api callbacks */
4762 
4763  /* flags */
4765 
4766  /* props */
4768 }
4769 
4772 /* -------------------------------------------------------------------- */
4777 {
4778  if (ED_operator_editmesh(C)) {
4779  Object *obedit = CTX_data_edit_object(C);
4780  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4781  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
4782 
4783  const ListBase *defbase = BKE_object_defgroup_list(obedit);
4784  if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
4785  CTX_wm_operator_poll_msg_set(C, "Must be in vertex selection mode");
4786  }
4787  else if (BLI_listbase_is_empty(defbase) || cd_dvert_offset == -1) {
4788  CTX_wm_operator_poll_msg_set(C, "No weights/vertex groups on object");
4789  }
4790  else {
4791  return true;
4792  }
4793  }
4794  return false;
4795 }
4796 
4798 {
4799  const bool extend = RNA_boolean_get(op->ptr, "extend");
4800  ViewLayer *view_layer = CTX_data_view_layer(C);
4801 
4802  uint objects_len = 0;
4804  view_layer, CTX_wm_view3d(C), &objects_len);
4805 
4806  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4807  Object *obedit = objects[ob_index];
4808  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4809 
4810  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
4811 
4812  if (cd_dvert_offset == -1) {
4813  continue;
4814  }
4815 
4816  BMVert *eve;
4817  BMIter iter;
4818 
4819  bool changed = false;
4820 
4821  if (!extend) {
4822  if (em->bm->totvertsel) {
4824  changed = true;
4825  }
4826  }
4827 
4828  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
4829  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
4830  MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
4831  /* no dv or dv set with no weight */
4832  if (ELEM(NULL, dv, dv->dw)) {
4833  BM_vert_select_set(em->bm, eve, true);
4834  changed = true;
4835  }
4836  }
4837  }
4838 
4839  if (changed) {
4843  }
4844  }
4845  MEM_freeN(objects);
4846  return OPERATOR_FINISHED;
4847 }
4848 
4850 {
4851  /* identifiers */
4852  ot->name = "Select Ungrouped";
4853  ot->idname = "MESH_OT_select_ungrouped";
4854  ot->description = "Select vertices without a group";
4855 
4856  /* api callbacks */
4859 
4860  /* flags */
4862 
4863  RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
4864 }
4865 
4868 /* -------------------------------------------------------------------- */
4872 enum {
4876 };
4877 
4879 {
4881  ViewLayer *view_layer = CTX_data_view_layer(C);
4882  Object *obedit = CTX_data_edit_object(C);
4883  BMEditMesh *em = BKE_editmesh_from_object(obedit);
4884  BMVert *v_act = BM_mesh_active_vert_get(em->bm);
4885  const int orientation = RNA_enum_get(op->ptr, "orientation");
4886  const int axis = RNA_enum_get(op->ptr, "axis");
4887  const int sign = RNA_enum_get(op->ptr, "sign");
4888 
4889  if (v_act == NULL) {
4890  BKE_report(
4891  op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)");
4892  return OPERATOR_CANCELLED;
4893  }
4894 
4895  const float limit = RNA_float_get(op->ptr, "threshold");
4896 
4897  float value;
4898  float axis_mat[3][3];
4899 
4900  /* 3D view variables may be NULL, (no need to check in poll function). */
4902  view_layer,
4903  CTX_wm_view3d(C),
4905  obedit,
4906  obedit,
4907  orientation,
4909  axis_mat);
4910 
4911  const float *axis_vector = axis_mat[axis];
4912 
4913  {
4914  float vertex_world[3];
4915  mul_v3_m4v3(vertex_world, obedit->obmat, v_act->co);
4916  value = dot_v3v3(axis_vector, vertex_world);
4917  }
4918 
4919  if (sign == SELECT_AXIS_NEG) {
4920  value += limit;
4921  }
4922  else if (sign == SELECT_AXIS_POS) {
4923  value -= limit;
4924  }
4925 
4926  uint objects_len = 0;
4928  view_layer, CTX_wm_view3d(C), &objects_len);
4929  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4930  Object *obedit_iter = objects[ob_index];
4931  BMEditMesh *em_iter = BKE_editmesh_from_object(obedit_iter);
4932  BMesh *bm = em_iter->bm;
4933 
4934  if (bm->totvert == bm->totvertsel) {
4935  continue;
4936  }
4937 
4938  BMIter iter;
4939  BMVert *v;
4940  bool changed = false;
4941 
4942  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
4944  float v_iter_world[3];
4945  mul_v3_m4v3(v_iter_world, obedit_iter->obmat, v->co);
4946  const float value_iter = dot_v3v3(axis_vector, v_iter_world);
4947  switch (sign) {
4948  case SELECT_AXIS_ALIGN:
4949  if (fabsf(value_iter - value) < limit) {
4950  BM_vert_select_set(bm, v, true);
4951  changed = true;
4952  }
4953  break;
4954  case SELECT_AXIS_NEG:
4955  if (value_iter < value) {
4956  BM_vert_select_set(bm, v, true);
4957  changed = true;
4958  }
4959  break;
4960  case SELECT_AXIS_POS:
4961  if (value_iter > value) {
4962  BM_vert_select_set(bm, v, true);
4963  changed = true;
4964  }
4965  break;
4966  }
4967  }
4968  }
4969  if (changed) {
4970  EDBM_selectmode_flush(em_iter);
4971  WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data);
4972  DEG_id_tag_update(obedit_iter->data, ID_RECALC_SELECT);
4973  }
4974  }
4975  MEM_freeN(objects);
4976  return OPERATOR_FINISHED;
4977 }
4978 
4980 {
4981  static const EnumPropertyItem axis_sign_items[] = {
4982  {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""},
4983  {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""},
4984  {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""},
4985  {0, NULL, 0, NULL, NULL},
4986  };
4987 
4988  /* identifiers */
4989  ot->name = "Select Axis";
4990  ot->description = "Select all data in the mesh on a single axis";
4991  ot->idname = "MESH_OT_select_axis";
4992 
4993  /* api callbacks */
4996 
4997  /* flags */
4999 
5000  /* properties */
5001  RNA_def_enum(ot->srna,
5002  "orientation",
5005  "Axis Mode",
5006  "Axis orientation");
5007  RNA_def_enum(ot->srna, "sign", axis_sign_items, SELECT_AXIS_POS, "Axis Sign", "Side to select");
5008  RNA_def_enum(ot->srna,
5009  "axis",
5011  0,
5012  "Axis",
5013  "Select the axis to compare each vertex on");
5014  RNA_def_float(
5015  ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f);
5016 }
5017 
5020 /* -------------------------------------------------------------------- */
5025 {
5026  ViewLayer *view_layer = CTX_data_view_layer(C);
5027  uint objects_len = 0;
5029  view_layer, CTX_wm_view3d(C), &objects_len);
5030  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5031  Object *obedit = objects[ob_index];
5032  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5033 
5034  if (em->bm->totfacesel == 0) {
5035  continue;
5036  }
5037  BMFace *f;
5038  BMEdge *e;
5039  BMIter iter;
5040 
5042 
5043  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
5044  BMLoop *l1, *l2;
5045  BMIter liter1, liter2;
5046 
5047  BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
5048  int tot = 0, totsel = 0;
5049 
5050  BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
5051  tot++;
5052  totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
5053  }
5054 
5055  if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) {
5057  }
5058  }
5059  }
5060 
5062 
5063  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
5065  BM_edge_select_set(em->bm, e, true);
5066  }
5067  }
5068 
5069  /* If in face-only select mode, switch to edge select mode so that
5070  * an edge-only selection is not inconsistent state */
5071  if (em->selectmode == SCE_SELECT_FACE) {
5073  EDBM_selectmode_set(em);
5075  }
5076 
5079  }
5080  MEM_freeN(objects);
5081 
5082  return OPERATOR_FINISHED;
5083 }
5084 
5086 {
5087  /* identifiers */
5088  ot->name = "Select Boundary Loop";
5089  ot->idname = "MESH_OT_region_to_loop";
5090  ot->description = "Select boundary edges around the selected faces";
5091 
5092  /* api callbacks */
5095 
5096  /* flags */
5098 }
5099 
5102 /* -------------------------------------------------------------------- */
5106 static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ***region_out)
5107 {
5108  BMFace **region = NULL;
5109  BMFace **stack = NULL;
5110  BLI_array_declare(region);
5111  BLI_array_declare(stack);
5112  BMFace *f;
5113 
5114  BLI_array_append(stack, l->f);
5115  BLI_gset_insert(visit_face_set, l->f);
5116 
5117  while (BLI_array_len(stack) > 0) {
5118  BMIter liter1, liter2;
5119  BMLoop *l1, *l2;
5120 
5121  f = BLI_array_pop(stack);
5122  BLI_array_append(region, f);
5123 
5124  BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
5125  if (BM_elem_flag_test(l1->e, flag)) {
5126  continue;
5127  }
5128 
5129  BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
5130  /* avoids finding same region twice
5131  * (otherwise) the logic works fine without */
5132  if (BM_elem_flag_test(l2->f, BM_ELEM_TAG)) {
5133  continue;
5134  }
5135 
5136  if (BLI_gset_add(visit_face_set, l2->f)) {
5137  BLI_array_append(stack, l2->f);
5138  }
5139  }
5140  }
5141  }
5142 
5143  BLI_array_free(stack);
5144 
5145  *region_out = region;
5146  return BLI_array_len(region);
5147 }
5148 
5149 static int verg_radial(const void *va, const void *vb)
5150 {
5151  const BMEdge *e_a = *((const BMEdge **)va);
5152  const BMEdge *e_b = *((const BMEdge **)vb);
5153 
5154  const int a = BM_edge_face_count(e_a);
5155  const int b = BM_edge_face_count(e_b);
5156 
5157  if (a > b) {
5158  return -1;
5159  }
5160  if (a < b) {
5161  return 1;
5162  }
5163  return 0;
5164 }
5165 
5172 static int loop_find_regions(BMEditMesh *em, const bool selbigger)
5173 {
5174  GSet *visit_face_set;
5175  BMIter iter;
5176  const int edges_len = em->bm->totedgesel;
5177  BMEdge *e, **edges;
5178  int count = 0, i;
5179 
5180  visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len);
5181  edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
5182 
5183  i = 0;
5184  BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
5186  edges[i++] = e;
5188  }
5189  else {
5191  }
5192  }
5193 
5194  /* sort edges by radial cycle length */
5195  qsort(edges, edges_len, sizeof(*edges), verg_radial);
5196 
5197  for (i = 0; i < edges_len; i++) {
5198  BMIter liter;
5199  BMLoop *l;
5200  BMFace **region = NULL, **region_out;
5201  int c, tot = 0;
5202 
5203  e = edges[i];
5204 
5205  if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
5206  continue;
5207  }
5208 
5209  BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
5210  if (BLI_gset_haskey(visit_face_set, l->f)) {
5211  continue;
5212  }
5213 
5214  c = loop_find_region(l, BM_ELEM_SELECT, visit_face_set, &region_out);
5215 
5216  if (!region || (selbigger ? c >= tot : c < tot)) {
5217  /* this region is the best seen so far */
5218  tot = c;
5219  if (region) {
5220  /* free the previous best */
5221  MEM_freeN(region);
5222  }
5223  /* track the current region as the new best */
5224  region = region_out;
5225  }
5226  else {
5227  /* this region is not as good as best so far, just free it */
5228  MEM_freeN(region_out);
5229  }
5230  }
5231 
5232  if (region) {
5233  int j;
5234 
5235  for (j = 0; j < tot; j++) {
5236  BM_elem_flag_enable(region[j], BM_ELEM_TAG);
5237  BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) {
5239  }
5240  }
5241 
5242  count += tot;
5243 
5244  MEM_freeN(region);
5245  }
5246  }
5247 
5248  MEM_freeN(edges);
5249  BLI_gset_free(visit_face_set, NULL);
5250 
5251  return count;
5252 }
5253 
5255 {
5256  const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger");
5257 
5258  ViewLayer *view_layer = CTX_data_view_layer(C);
5259  uint objects_len = 0;
5261  view_layer, CTX_wm_view3d(C), &objects_len);
5262  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5263  Object *obedit = objects[ob_index];
5264  BMEditMesh *em = BKE_editmesh_from_object(obedit);
5265 
5266  if (em->bm->totedgesel == 0) {
5267  continue;
5268  }
5269 
5270  BMIter iter;
5271  BMFace *f;
5272 
5273  /* find the set of regions with smallest number of total faces */
5275  const int a = loop_find_regions(em, select_bigger);
5276  const int b = loop_find_regions(em, !select_bigger);
5277 
5279  loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger);
5280 
5282 
5283  BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
5285  BM_face_select_set(em->bm, f, true);
5286  }
5287  }
5288 
5290 
5293  }
5294  MEM_freeN(objects);
5295 
5296  return OPERATOR_FINISHED;
5297 }
5298 
5300 {
5301  /* identifiers */
5302  ot->name = "Select Loop Inner-Region";
5303  ot->idname = "MESH_OT_loop_to_region";
5304  ot->description = "Select region of faces inside of a selected loop of edges";
5305 
5306  /* api callbacks */
5309 
5310  /* flags */
5312 
5314  "select_bigger",
5315  0,
5316  "Select Bigger",
5317  "Select bigger regions instead of smaller ones");
5318 }
5319 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:824
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const struct CustomData *data, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
support for deformation groups and hooks.
const struct ListBase * BKE_object_defgroup_list(const struct Object *ob)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:539
#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:536
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:546
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_pop(arr)
Definition: BLI_array.h:122
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_len(arr)
Definition: BLI_array.h:63
#define BLI_array_free(arr)
Definition: BLI_array.h:113
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
struct GSet GSet
Definition: BLI_ghash.h:340
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1007
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
void BLI_gset_insert(GSet *gs, void *key)
Definition: BLI_ghash.c:962
GSet * BLI_gset_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:969
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition: BLI_heap.c:202
void void float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:357
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:279
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:301
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition: BLI_heap.c:182
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:245
void * BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:362
HeapNode * BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:289
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:269
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:221
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
int BLI_listbase_count_at_most(const struct ListBase *listbase, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
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:3274
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:579
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:563
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
bool invert_m3(float R[3][3])
Definition: math_matrix.c:1171
#define DEG2RADF(_deg)
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition: math_vector.c:14
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 interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
void mid_v2_v2v2(float r[2], const float a[2], const float b[2])
Definition: math_vector.c:244
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:237
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:445
Random number functions.
void BLI_array_randomize(void *data, unsigned int elem_size, unsigned int elem_num, unsigned int seed)
Definition: rand.cc:188
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
unsigned int uint
Definition: BLI_sys_types.h:67
#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_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define TIP_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
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:834
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ 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_AROUND_ACTIVE
@ V3D_ORIENT_LOCAL
#define RV3D_CLIPPING
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int center[2], uint id_min, uint id_max, uint *dist)
void DRW_select_buffer_context_create(struct Base **bases, uint bases_len, short select_mode)
bool DRW_select_buffer_elem_get(uint sel_id, uint *r_elem, uint *r_base_index, char *r_elem_type)
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_update(struct Mesh *me, const struct EDBMUpdate_Params *params)
struct BMFace * EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *f)
void EDBM_flag_enable_all(struct BMEditMesh *em, char hflag)
void EDBM_select_flush(struct BMEditMesh *em)
struct BMVert * EDBM_verts_mirror_get(struct BMEditMesh *em, struct BMVert *v)
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em)
void EDBM_select_more(struct BMEditMesh *em, bool use_face_step)
void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag)
void EDBM_deselect_flush(struct BMEditMesh *em)
void EDBM_select_less(struct BMEditMesh *em, bool use_face_step)
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology)
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode)
void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode)
Definition: mesh_data.cc:1378
struct BMEdge * EDBM_verts_mirror_get_edge(struct BMEditMesh *em, struct BMEdge *e)
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:447
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:433
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
@ SEL_OP_AND
@ SEL_OP_XOR
short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene, struct ViewLayer *view_layer, const struct View3D *v3d, const struct RegionView3D *rv3d, struct Object *ob, struct Object *obedit, short orientation_index, int pivot_point, float r_mat[3][3])
#define V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT
Definition: ED_view3d.h:270
eV3DProjTest
Definition: ED_view3d.h:233
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:237
@ V3D_PROJ_TEST_CLIP_BB
Definition: ED_view3d.h:235
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
void mesh_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index), void *userData, eV3DProjTest clip_flag)
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact)
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], bool is_local)
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_normal[3], bool do_clip_planes)
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, eV3DProjTest clip_flag)
#define V3D_PROJ_TEST_CLIP_DEFAULT
Definition: ED_view3d.h:264
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
#define XRAY_FLAG_ENABLED(v3d)
Definition: ED_view3d.h:1298
void view3d_operator_needs_opengl(const struct bContext *C)
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:166
int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, float dist)
Definition: view3d_draw.c:2195
float ED_view3d_select_dist_px(void)
void mesh_foreachScreenFace(struct ViewContext *vc, void(*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index), void *userData, eV3DProjTest clip_flag)
_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.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
#define NC_SCENE
Definition: WM_types.h:328
#define ND_TOOLSETTINGS
Definition: WM_types.h:397
#define NC_MATERIAL
Definition: WM_types.h:330
#define ND_SELECT
Definition: WM_types.h:455
@ KM_CTRL
Definition: WM_types.h:239
@ KM_SHIFT
Definition: WM_types.h:238
#define ND_SHADING_LINKS
Definition: WM_types.h:427
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ 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_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:111
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
#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.cc:109
BMEdge * BM_edge_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.cc:692
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
Definition: bmesh_mesh.cc:75
BMFace * BM_face_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.cc:700
BMVert * BM_vert_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.cc:684
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:115
#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)
BMESH OPSTACK PUSH.
#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:875
bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide)
Definition: bmesh_query.c:1950
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:2094
bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag)
Definition: bmesh_query.c:2003
bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag)
Definition: bmesh_query.c:1989
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
Definition: bmesh_query.c:553
bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
Definition: bmesh_query.c:1914
bool BM_vert_is_manifold(const BMVert *v)
Definition: bmesh_query.c:705
int BM_edge_face_count(const BMEdge *e)
Definition: bmesh_query.c:629
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
Definition: bmesh_query.c:1984
float BM_edge_calc_length(const BMEdge *e)
Definition: bmesh_query.c:528
bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
Definition: bmesh_query.c:1932
bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
Definition: bmesh_query.c:1968
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:248
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:49
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:40
void * BMW_step(BMWalker *walker)
Step Walker.
@ BMW_BREADTH_FIRST
Definition: bmesh_walkers.h:15
#define BMW_NIL_LAY
@ BMW_FLAG_NOP
Definition: bmesh_walkers.h:19
@ BMW_FLAG_TEST_HIDDEN
Definition: bmesh_walkers.h:20
#define BMW_MASK_NOP
Definition: bmesh_walkers.h:54
@ 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)
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
#define cosf(x)
Definition: cuda/compat.h:101
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)
@ SELECT_AXIS_ALIGN
@ SELECT_AXIS_POS
@ SELECT_AXIS_NEG
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)
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)
bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
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)
static char * edbm_select_mode_get_description(struct bContext *UNUSED(C), struct wmOperatorType *UNUSED(op), struct PointerRNA *values)
void MESH_OT_select_ungrouped(wmOperatorType *ot)
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, uint object_index, uint 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:43
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static char faces[256]
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
double sign(double arg)
Definition: utility.h:250
static void area(int d1, int d2, int e1, int e2, float weights[2])
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
SocketIndexByIdentifierMap * map
return ret
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3421
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3402
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:5301
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
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:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
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:3806
void RNA_def_property_float_default(PropertyRNA *prop, float value)
Definition: rna_define.c:2022
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
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:3597
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:4016
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:3783
const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]
Definition: rna_mesh.c:36
const EnumPropertyItem rna_enum_axis_flag_xyz_items[]
Definition: rna_modifier.c:622
const EnumPropertyItem rna_enum_axis_xyz_items[]
Definition: rna_modifier.c:615
const EnumPropertyItem rna_enum_mesh_select_mode_items[]
Definition: rna_scene.c:131
const EnumPropertyItem rna_enum_transform_orientation_items[]
Definition: rna_scene.c:591
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
short mat_nr
Definition: BKE_editmesh.h:54
struct BMEditSelection * next
Definition: bmesh_marking.h:10
BMHeader head
Definition: bmesh_class.h:243
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:267
BMHeader head
Definition: bmesh_class.h:255
float no[3]
Definition: bmesh_class.h:271
char htype
Definition: bmesh_class.h:64
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
struct BMEdge * e
Definition: bmesh_class.h:97
BMHeader head
Definition: bmesh_class.h:85
BMWOrder order
Definition: bmesh_walkers.h:30
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:43
char name[66]
Definition: DNA_ID.h:378
void * data
Definition: DNA_listBase.h:26
void * first
Definition: DNA_listBase.h:31
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
unsigned short actfmap
float obmat[4][4]
void * data
ListBase fmaps
struct ToolSettings * toolsettings
struct Depsgraph * depsgraph
Definition: ED_view3d.h:64
int mval[2]
Definition: ED_view3d.h:74
struct Scene * scene
Definition: ED_view3d.h:65
struct ARegion * region
Definition: ED_view3d.h:69
struct ViewLayer * view_layer
Definition: ED_view3d.h:66
struct BMEditMesh * em
Definition: ED_view3d.h:73
struct Object * obact
Definition: ED_view3d.h:67
struct Object * obedit
Definition: ED_view3d.h:68
struct View3D * v3d
Definition: ED_view3d.h:70
struct RegionView3D * rv3d
Definition: ED_view3d.h:72
struct Base * basact
int mval[2]
Definition: WM_types.h:684
uint8_t modifier
Definition: WM_types.h:693
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:966
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
bool WM_cursor_test_motion_and_update(const int mval[2])
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:3479
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)