Fix bug selecting verts in mixed edge/vert mode
[blender.git] / source / blender / editors / mesh / editmesh_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2004 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/mesh/editmesh_select.c
29  *  \ingroup edmesh
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_bitmap.h"
35 #include "BLI_bitmap_draw_2d.h"
36 #include "BLI_listbase.h"
37 #include "BLI_linklist.h"
38 #include "BLI_linklist_stack.h"
39 #include "BLI_math.h"
40 #include "BLI_math_bits.h"
41 #include "BLI_rand.h"
42 #include "BLI_array.h"
43
44 #include "BKE_context.h"
45 #include "BKE_report.h"
46 #include "BKE_paint.h"
47 #include "BKE_editmesh.h"
48 #include "BKE_layer.h"
49
50 #include "IMB_imbuf_types.h"
51 #include "IMB_imbuf.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58 #include "RNA_enum_types.h"
59
60 #include "ED_object.h"
61 #include "ED_mesh.h"
62 #include "ED_screen.h"
63 #include "ED_transform.h"
64 #include "ED_select_utils.h"
65 #include "ED_view3d.h"
66
67 #include "DNA_mesh_types.h"
68 #include "DNA_meshdata_types.h"
69 #include "DNA_object_types.h"
70
71 #include "UI_resources.h"
72
73 #include "bmesh_tools.h"
74
75 #include "DEG_depsgraph.h"
76 #include "DEG_depsgraph_query.h"
77
78 #include "mesh_intern.h"  /* own include */
79
80 /* use bmesh operator flags for a few operators */
81 #define BMO_ELE_TAG 1
82
83 /* -------------------------------------------------------------------- */
84 /** \name Select Mirror
85  * \{ */
86
87 void EDBM_select_mirrored(
88         BMEditMesh *em, const int axis, const bool extend,
89         int *r_totmirr, int *r_totfail)
90 {
91         Mesh *me = (Mesh *)em->ob->data;
92         BMesh *bm = em->bm;
93         BMIter iter;
94         int totmirr = 0;
95         int totfail = 0;
96         bool use_topology = (me && (me->editflag & ME_EDIT_MIRROR_TOPO));
97
98         *r_totmirr = *r_totfail = 0;
99
100         /* select -> tag */
101         if (bm->selectmode & SCE_SELECT_VERTEX) {
102                 BMVert *v;
103                 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
104                         BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
105                 }
106         }
107         else if (em->selectmode & SCE_SELECT_EDGE) {
108                 BMEdge *e;
109                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
110                         BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
111                 }
112         }
113         else {
114                 BMFace *f;
115                 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
116                         BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
117                 }
118         }
119
120         EDBM_verts_mirror_cache_begin(em, axis, true, true, use_topology);
121
122         if (!extend)
123                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
124
125
126         if (bm->selectmode & SCE_SELECT_VERTEX) {
127                 BMVert *v;
128                 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
129                         if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_TAG)) {
130                                 BMVert *v_mirr = EDBM_verts_mirror_get(em, v);
131                                 if (v_mirr && !BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) {
132                                         BM_vert_select_set(bm, v_mirr, true);
133                                         totmirr++;
134                                 }
135                                 else {
136                                         totfail++;
137                                 }
138                         }
139                 }
140         }
141         else if (em->selectmode & SCE_SELECT_EDGE) {
142                 BMEdge *e;
143                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
144                         if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_TAG)) {
145                                 BMEdge *e_mirr = EDBM_verts_mirror_get_edge(em, e);
146                                 if (e_mirr && !BM_elem_flag_test(e_mirr, BM_ELEM_HIDDEN)) {
147                                         BM_edge_select_set(bm, e_mirr, true);
148                                         totmirr++;
149                                 }
150                                 else {
151                                         totfail++;
152                                 }
153                         }
154                 }
155         }
156         else {
157                 BMFace *f;
158                 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
159                         if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_TAG)) {
160                                 BMFace *f_mirr = EDBM_verts_mirror_get_face(em, f);
161                                 if (f_mirr && !BM_elem_flag_test(f_mirr, BM_ELEM_HIDDEN)) {
162                                         BM_face_select_set(bm, f_mirr, true);
163                                         totmirr++;
164                                 }
165                                 else {
166                                         totfail++;
167                                 }
168                         }
169                 }
170         }
171
172         EDBM_verts_mirror_cache_end(em);
173
174         *r_totmirr = totmirr;
175         *r_totfail = totfail;
176 }
177
178 /** \} */
179
180 /* -------------------------------------------------------------------- */
181 /** \name Select Auto-Merge
182  *
183  * Used after transform operations.
184  * \{ */
185
186 void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
187 {
188         bool ok;
189         BMEditMesh *em = BKE_editmesh_from_object(obedit);
190
191         ok = BMO_op_callf(
192                 em->bm, BMO_FLAG_DEFAULTS,
193                 "automerge verts=%hv dist=%f",
194                 hflag, scene->toolsettings->doublimit);
195
196         if (LIKELY(ok) && update) {
197                 EDBM_update_generic(em, true, true);
198         }
199 }
200
201 /** \} */
202
203 /* -------------------------------------------------------------------- */
204 /** \name Back-Buffer OpenGL Selection
205  * \{ */
206
207 unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0;    /* set in drawobject.c ... for colorindices */
208
209 /* facilities for box select and circle select */
210 static BLI_bitmap *selbuf = NULL;
211
212 static BLI_bitmap *edbm_backbuf_alloc(const int size)
213 {
214         return BLI_BITMAP_NEW(size, "selbuf");
215 }
216
217 /* reads rect, and builds selection array for quick lookup */
218 /* returns if all is OK */
219 bool EDBM_backbuf_border_init(
220         ViewContext *vc, short xmin,
221         short ymin, short xmax, short ymax)
222 {
223         struct ImBuf *buf;
224         unsigned int *dr;
225         int a;
226
227         if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) {
228                 return false;
229         }
230
231         buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
232         if ((buf == NULL) || (bm_vertoffs == 0)) {
233                 return false;
234         }
235
236         dr = buf->rect;
237
238         /* build selection lookup */
239         selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
240
241         a = (xmax - xmin + 1) * (ymax - ymin + 1);
242         while (a--) {
243                 if (*dr > 0 && *dr <= bm_vertoffs) {
244                         BLI_BITMAP_ENABLE(selbuf, *dr);
245                 }
246                 dr++;
247         }
248         IMB_freeImBuf(buf);
249         return true;
250 }
251
252 bool EDBM_backbuf_check(unsigned int index)
253 {
254         /* odd logic, if selbuf is NULL we assume no zbuf-selection is enabled
255          * and just ignore the depth buffer, this is error prone since its possible
256          * code doesn't set the depth buffer by accident, but leave for now. - Campbell */
257         if (selbuf == NULL)
258                 return true;
259
260         if (index > 0 && index <= bm_vertoffs)
261                 return BLI_BITMAP_TEST_BOOL(selbuf, index);
262
263         return false;
264 }
265
266 void EDBM_backbuf_free(void)
267 {
268         if (selbuf) MEM_freeN(selbuf);
269         selbuf = NULL;
270 }
271
272 struct LassoMaskData {
273         unsigned int *px;
274         int width;
275 };
276
277 static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
278 {
279         struct LassoMaskData *data = user_data;
280         unsigned int *px = &data->px[(y * data->width) + x];
281         do {
282                 *px = true;
283                 px++;
284         } while (++x != x_end);
285 }
286
287
288 /* mcords is a polygon mask
289  * - grab backbuffer,
290  * - draw with black in backbuffer,
291  * - grab again and compare
292  * returns 'OK'
293  */
294 bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
295 {
296         unsigned int *dr, *dr_mask, *dr_mask_arr;
297         struct ImBuf *buf;
298         int a;
299         struct LassoMaskData lasso_mask_data;
300
301         /* method in use for face selecting too */
302         if (vc->obedit == NULL) {
303                 if (!BKE_paint_select_elem_test(vc->obact)) {
304                         return false;
305                 }
306         }
307         else if (!V3D_IS_ZBUF(vc->v3d)) {
308                 return false;
309         }
310
311         buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
312         if ((buf == NULL) || (bm_vertoffs == 0)) {
313                 return false;
314         }
315
316         dr = buf->rect;
317
318         dr_mask = dr_mask_arr = MEM_callocN(sizeof(*dr_mask) * buf->x * buf->y, __func__);
319         lasso_mask_data.px = dr_mask;
320         lasso_mask_data.width = (xmax - xmin) + 1;
321
322         BLI_bitmap_draw_2d_poly_v2i_n(
323                xmin, ymin, xmax + 1, ymax + 1,
324                mcords, tot,
325                edbm_mask_lasso_px_cb, &lasso_mask_data);
326
327         /* build selection lookup */
328         selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
329
330         a = (xmax - xmin + 1) * (ymax - ymin + 1);
331         while (a--) {
332                 if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) {
333                         BLI_BITMAP_ENABLE(selbuf, *dr);
334                 }
335                 dr++; dr_mask++;
336         }
337         IMB_freeImBuf(buf);
338         MEM_freeN(dr_mask_arr);
339
340         return true;
341 }
342
343 /* circle shaped sample area */
344 bool EDBM_backbuf_circle_init(
345         ViewContext *vc,
346         short xs, short ys, short rads)
347 {
348         struct ImBuf *buf;
349         unsigned int *dr;
350         short xmin, ymin, xmax, ymax, xc, yc;
351         int radsq;
352
353         /* method in use for face selecting too */
354         if (vc->obedit == NULL) {
355                 if (!BKE_paint_select_elem_test(vc->obact)) {
356                         return false;
357                 }
358         }
359         else if (!V3D_IS_ZBUF(vc->v3d)) {
360                 return false;
361         }
362
363         xmin = xs - rads; xmax = xs + rads;
364         ymin = ys - rads; ymax = ys + rads;
365         buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
366         if ((buf == NULL) || (bm_vertoffs == 0)) {
367                 return false;
368         }
369
370         dr = buf->rect;
371
372         /* build selection lookup */
373         selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
374         radsq = rads * rads;
375         for (yc = -rads; yc <= rads; yc++) {
376                 for (xc = -rads; xc <= rads; xc++, dr++) {
377                         if (xc * xc + yc * yc < radsq) {
378                                 if (*dr > 0 && *dr <= bm_vertoffs) {
379                                         BLI_BITMAP_ENABLE(selbuf, *dr);
380                                 }
381                         }
382                 }
383         }
384
385         IMB_freeImBuf(buf);
386         return true;
387
388 }
389
390 /** \} */
391
392 /* -------------------------------------------------------------------- */
393 /** \name Find Nearest Vert/Edge/Face
394  *
395  * \note Screen-space manhatten distances are used here,
396  * since its faster and good enough for the purpose of selection.
397  *
398  * \note \a dist_bias is used so we can bias against selected items.
399  * when choosing between elements of a single type, but return the real distance
400  * to avoid the bias interfering with distance comparisons when mixing types.
401  * \{ */
402
403 #define FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, select_mode_required) \
404         short select_mode = select_mode_required; \
405         bool fake_select_mode = (select_mode & (vc)->scene->toolsettings->selectmode) == 0; \
406         if (fake_select_mode) { \
407                 (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \
408         } ((void)0)
409
410 #define FAKE_SELECT_MODE_END(vc, fake_select_mode) \
411         if (fake_select_mode) { \
412                 (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \
413         } ((void)0)
414
415 #define FIND_NEAR_SELECT_BIAS 5
416 #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
417
418 struct NearestVertUserData_Hit {
419         float   dist;
420         float   dist_bias;
421         int     index;
422         BMVert *vert;
423 };
424
425 struct NearestVertUserData {
426         float mval_fl[2];
427         bool use_select_bias;
428         bool use_cycle;
429         int cycle_index_prev;
430
431         struct NearestVertUserData_Hit hit;
432         struct NearestVertUserData_Hit hit_cycle;
433 };
434
435 static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
436 {
437         struct NearestVertUserData *data = userData;
438         float dist_test, dist_test_bias;
439
440         dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
441
442         if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
443                 dist_test_bias += FIND_NEAR_SELECT_BIAS;
444         }
445
446         if (dist_test_bias < data->hit.dist_bias) {
447                 data->hit.dist_bias = dist_test_bias;
448                 data->hit.dist = dist_test;
449                 data->hit.index = index;
450                 data->hit.vert = eve;
451         }
452
453         if (data->use_cycle) {
454                 if ((data->hit_cycle.vert == NULL) &&
455                     (index > data->cycle_index_prev) &&
456                     (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
457                 {
458                         data->hit_cycle.dist_bias = dist_test_bias;
459                         data->hit_cycle.dist = dist_test;
460                         data->hit_cycle.index = index;
461                         data->hit_cycle.vert = eve;
462                 }
463         }
464 }
465
466 /**
467  * Nearest vertex under the cursor.
468  *
469  * \param r_dist: (in/out), minimal distance to the nearest and at the end, actual distance
470  * \param use_select_bias:
471  * - When true, selected vertice are given a 5 pixel bias to make them further than unselect verts.
472  * - When false, unselected vertice are given the bias.
473  * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
474  */
475 BMVert *EDBM_vert_find_nearest_ex(
476         ViewContext *vc, float *r_dist,
477         const bool use_select_bias, bool use_cycle)
478 {
479         BMesh *bm = vc->em->bm;
480
481         if (V3D_IS_ZBUF(vc->v3d)) {
482                 const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
483                 float dist_test;
484                 unsigned int index;
485                 BMVert *eve;
486
487                 /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
488                 {
489                         FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX);
490                         ED_view3d_backbuf_validate_with_select_mode(vc, select_mode);
491
492                         index = ED_view3d_backbuf_sample_rect(
493                                     vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
494                         eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
495
496                         FAKE_SELECT_MODE_END(vc, fake_select_mode);
497                 }
498
499                 if (eve) {
500                         if (dist_test < *r_dist) {
501                                 *r_dist = dist_test;
502                                 return eve;
503                         }
504                 }
505                 return NULL;
506         }
507         else {
508                 struct NearestVertUserData data = {{0}};
509                 const struct NearestVertUserData_Hit *hit;
510                 const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
511
512                 static int prev_select_index = 0;
513                 static const BMVert *prev_select_elem = NULL;
514
515                 if ((use_cycle == false) ||
516                     (prev_select_elem && (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index))))
517                 {
518                         prev_select_index = 0;
519                         prev_select_elem = NULL;
520                 }
521
522                 data.mval_fl[0] = vc->mval[0];
523                 data.mval_fl[1] = vc->mval[1];
524                 data.use_select_bias = use_select_bias;
525                 data.use_cycle = use_cycle;
526                 data.hit.dist      = data.hit_cycle.dist = \
527                 data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
528                 data.cycle_index_prev = prev_select_index;
529
530                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
531                 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag);
532
533                 hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit;
534                 *r_dist = hit->dist;
535
536                 prev_select_elem = hit->vert;
537                 prev_select_index = hit->index;
538
539                 return hit->vert;
540         }
541 }
542
543 BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist)
544 {
545         return EDBM_vert_find_nearest_ex(vc, r_dist, false, false);
546 }
547
548 /* find the distance to the edge we already have */
549 struct NearestEdgeUserData_ZBuf {
550         float mval_fl[2];
551         float dist;
552         const BMEdge *edge_test;
553 };
554
555 static void find_nearest_edge_center__doZBuf(
556         void *userData, BMEdge *eed,
557         const float screen_co_a[2], const float screen_co_b[2],
558         int UNUSED(index))
559 {
560         struct NearestEdgeUserData_ZBuf *data = userData;
561
562         if (eed == data->edge_test) {
563                 float dist_test;
564                 float screen_co_mid[2];
565
566                 mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
567                 dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
568
569                 if (dist_test < data->dist) {
570                         data->dist = dist_test;
571                 }
572         }
573 }
574
575 struct NearestEdgeUserData_Hit {
576         float   dist;
577         float   dist_bias;
578         int     index;
579         BMEdge *edge;
580
581         /* edges only, un-biased manhatten distance to which ever edge we pick
582          * (not used for choosing) */
583         float   dist_center;
584 };
585
586 struct NearestEdgeUserData {
587         ViewContext vc;
588         float mval_fl[2];
589         bool use_select_bias;
590         bool use_cycle;
591         int cycle_index_prev;
592
593         struct NearestEdgeUserData_Hit hit;
594         struct NearestEdgeUserData_Hit hit_cycle;
595 };
596
597 /* note; uses v3d, so needs active 3d window */
598 static void find_nearest_edge__doClosest(
599         void *userData, BMEdge *eed,
600         const float screen_co_a[2], const float screen_co_b[2],
601         int index)
602 {
603         struct NearestEdgeUserData *data = userData;
604         float dist_test, dist_test_bias;
605
606         float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
607         float screen_co[2];
608
609         if (fac <= 0.0f) {
610                 fac = 0.0f;
611                 copy_v2_v2(screen_co, screen_co_a);
612         }
613         else if (fac >= 1.0f) {
614                 fac = 1.0f;
615                 copy_v2_v2(screen_co, screen_co_b);
616         }
617         else {
618                 interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac);
619         }
620
621         dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
622
623         if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
624                 dist_test_bias += FIND_NEAR_SELECT_BIAS;
625         }
626
627         if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
628                 float vec[3];
629
630                 interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac);
631                 if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) {
632                         return;
633                 }
634         }
635
636         if (dist_test_bias < data->hit.dist_bias) {
637                 float screen_co_mid[2];
638
639                 data->hit.dist_bias = dist_test_bias;
640                 data->hit.dist = dist_test;
641                 data->hit.index = index;
642                 data->hit.edge = eed;
643
644                 mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
645                 data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
646         }
647
648         if (data->use_cycle) {
649                 if ((data->hit_cycle.edge == NULL) &&
650                     (index > data->cycle_index_prev) &&
651                     (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
652                 {
653                         float screen_co_mid[2];
654
655                         data->hit_cycle.dist_bias = dist_test_bias;
656                         data->hit_cycle.dist = dist_test;
657                         data->hit_cycle.index = index;
658                         data->hit_cycle.edge = eed;
659
660                         mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
661                         data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
662                 }
663         }
664 }
665
666 BMEdge *EDBM_edge_find_nearest_ex(
667         ViewContext *vc, float *r_dist,
668         float *r_dist_center,
669         const bool use_select_bias, const bool use_cycle,
670         BMEdge **r_eed_zbuf)
671 {
672         BMesh *bm = vc->em->bm;
673
674         if (V3D_IS_ZBUF(vc->v3d)) {
675                 const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
676                 float dist_test = 0.0f;
677                 unsigned int index;
678                 BMEdge *eed;
679
680                 /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
681                 {
682                         FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_EDGE);
683                         ED_view3d_backbuf_validate_with_select_mode(vc, select_mode);
684
685                         index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
686                         eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
687
688                         FAKE_SELECT_MODE_END(vc, fake_select_mode);
689                 }
690
691                 if (r_eed_zbuf) {
692                         *r_eed_zbuf = eed;
693                 }
694
695                 /* exception for faces (verts don't need this) */
696                 if (r_dist_center && eed) {
697                         struct NearestEdgeUserData_ZBuf data;
698
699                         data.mval_fl[0] = vc->mval[0];
700                         data.mval_fl[1] = vc->mval[1];
701                         data.dist = FLT_MAX;
702                         data.edge_test = eed;
703
704                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
705
706                         mesh_foreachScreenEdge(vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
707
708                         *r_dist_center = data.dist;
709                 }
710                 /* end exception */
711
712                 if (eed) {
713                         if (dist_test < *r_dist) {
714                                 *r_dist = dist_test;
715                                 return eed;
716                         }
717                 }
718                 return NULL;
719         }
720         else {
721                 struct NearestEdgeUserData data = {{0}};
722                 const struct NearestEdgeUserData_Hit *hit;
723                 /* interpolate along the edge before doing a clipping plane test */
724                 const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB;
725
726                 static int prev_select_index = 0;
727                 static const BMEdge *prev_select_elem = NULL;
728
729                 if ((use_cycle == false) ||
730                     (prev_select_elem && (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index))))
731                 {
732                         prev_select_index = 0;
733                         prev_select_elem = NULL;
734                 }
735
736                 data.vc = *vc;
737                 data.mval_fl[0] = vc->mval[0];
738                 data.mval_fl[1] = vc->mval[1];
739                 data.use_select_bias = use_select_bias;
740                 data.use_cycle = use_cycle;
741                 data.hit.dist      = data.hit_cycle.dist = \
742                 data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
743                 data.cycle_index_prev = prev_select_index;
744
745                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
746                 mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag);
747
748                 hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
749                 *r_dist = hit->dist;
750                 if (r_dist_center) {
751                         *r_dist_center = hit->dist_center;
752                 }
753
754                 prev_select_elem = hit->edge;
755                 prev_select_index = hit->index;
756
757                 return hit->edge;
758         }
759 }
760
761 BMEdge *EDBM_edge_find_nearest(
762         ViewContext *vc, float *r_dist)
763 {
764         return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
765 }
766
767 /* find the distance to the face we already have */
768 struct NearestFaceUserData_ZBuf {
769         float mval_fl[2];
770         float dist;
771         const BMFace *face_test;
772 };
773
774 static void find_nearest_face_center__doZBuf(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
775 {
776         struct NearestFaceUserData_ZBuf *data = userData;
777
778         if (efa == data->face_test) {
779                 const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
780
781                 if (dist_test < data->dist) {
782                         data->dist = dist_test;
783                 }
784         }
785 }
786
787
788 struct NearestFaceUserData_Hit {
789         float   dist;
790         float   dist_bias;
791         int     index;
792         BMFace *face;
793 };
794
795 struct NearestFaceUserData {
796         float mval_fl[2];
797         bool use_select_bias;
798         bool use_cycle;
799         int cycle_index_prev;
800
801         struct NearestFaceUserData_Hit hit;
802         struct NearestFaceUserData_Hit hit_cycle;
803 };
804
805 static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
806 {
807         struct NearestFaceUserData *data = userData;
808         float dist_test, dist_test_bias;
809
810         dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
811
812         if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
813                 dist_test_bias += FIND_NEAR_SELECT_BIAS;
814         }
815
816         if (dist_test_bias < data->hit.dist_bias) {
817                 data->hit.dist_bias = dist_test_bias;
818                 data->hit.dist = dist_test;
819                 data->hit.index = index;
820                 data->hit.face = efa;
821         }
822
823         if (data->use_cycle) {
824                 if ((data->hit_cycle.face == NULL) &&
825                     (index > data->cycle_index_prev) &&
826                     (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
827                 {
828                         data->hit_cycle.dist_bias = dist_test_bias;
829                         data->hit_cycle.dist = dist_test;
830                         data->hit_cycle.index = index;
831                         data->hit_cycle.face = efa;
832                 }
833         }
834 }
835
836
837 BMFace *EDBM_face_find_nearest_ex(
838         ViewContext *vc, float *r_dist,
839         float *r_dist_center,
840         const bool use_select_bias, const bool use_cycle,
841         BMFace **r_efa_zbuf)
842 {
843         BMesh *bm = vc->em->bm;
844
845         if (V3D_IS_ZBUF(vc->v3d)) {
846                 float dist_test = 0.0f;
847                 unsigned int index;
848                 BMFace *efa;
849
850                 {
851                         FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_FACE);
852                         ED_view3d_backbuf_validate_with_select_mode(vc, select_mode);
853
854                         index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
855                         efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
856
857                         FAKE_SELECT_MODE_END(vc, fake_select_mode);
858                 }
859
860                 if (r_efa_zbuf) {
861                         *r_efa_zbuf = efa;
862                 }
863
864                 /* exception for faces (verts don't need this) */
865                 if (r_dist_center && efa) {
866                         struct NearestFaceUserData_ZBuf data;
867
868                         data.mval_fl[0] = vc->mval[0];
869                         data.mval_fl[1] = vc->mval[1];
870                         data.dist = FLT_MAX;
871                         data.face_test = efa;
872
873                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
874
875                         mesh_foreachScreenFace(vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
876
877                         *r_dist_center = data.dist;
878                 }
879                 /* end exception */
880
881                 if (efa) {
882                         if (dist_test < *r_dist) {
883                                 *r_dist = dist_test;
884                                 return efa;
885                         }
886                 }
887                 return NULL;
888         }
889         else {
890                 struct NearestFaceUserData data = {{0}};
891                 const struct NearestFaceUserData_Hit *hit;
892                 const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
893
894                 static int prev_select_index = 0;
895                 static const BMFace *prev_select_elem = NULL;
896
897                 if ((use_cycle == false) ||
898                     (prev_select_elem && (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index))))
899                 {
900                         prev_select_index = 0;
901                         prev_select_elem = NULL;
902                 }
903
904                 data.mval_fl[0] = vc->mval[0];
905                 data.mval_fl[1] = vc->mval[1];
906                 data.use_select_bias = use_select_bias;
907                 data.use_cycle = use_cycle;
908                 data.hit.dist      = data.hit_cycle.dist = \
909                 data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
910                 data.cycle_index_prev = prev_select_index;
911
912                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
913                 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag);
914
915                 hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
916                 *r_dist = hit->dist;
917                 if (r_dist_center) {
918                         *r_dist_center = hit->dist;
919                 }
920
921                 prev_select_elem = hit->face;
922                 prev_select_index = hit->index;
923
924                 return hit->face;
925         }
926 }
927
928 BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
929 {
930         return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
931 }
932
933 #undef FIND_NEAR_SELECT_BIAS
934 #undef FIND_NEAR_CYCLE_THRESHOLD_MIN
935
936
937 /* best distance based on screen coords.
938  * use em->selectmode to define how to use
939  * selected vertices and edges get disadvantage
940  * return 1 if found one
941  */
942 static bool unified_findnearest(
943         ViewContext *vc, Base **bases, const uint bases_len,
944         int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
945 {
946         BMEditMesh *em = vc->em;
947         static short mval_prev[2] = {-1, -1};
948         /* only cycle while the mouse remains still */
949         const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
950         const float dist_init = ED_view3d_select_dist_px();
951         /* since edges select lines, we give dots advantage of ~20 pix */
952         const float dist_margin = (dist_init / 2);
953         float dist = dist_init;
954
955         struct {
956                 struct {
957                         BMVert *ele;
958                         int base_index;
959                 } v;
960                 struct {
961                         BMEdge *ele;
962                         int base_index;
963                 } e, e_zbuf;
964                 struct {
965                         BMFace *ele;
966                         int base_index;
967                 } f, f_zbuf;
968         } hit = {{NULL}};
969
970         /* TODO(campbell): perform selection as one pass
971          * instead of many smaller passes (which doesn't work for zbuf occlusion). */
972
973         /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
974
975         if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) {
976                 float dist_center = 0.0f;
977                 float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL;
978
979                 for (uint base_index = 0; base_index < bases_len; base_index++) {
980                         Base *base_iter = bases[base_index];
981                         Object *obedit = base_iter->object;
982                         ED_view3d_viewcontext_init_object(vc, obedit);
983                         BLI_assert(vc->em->selectmode == em->selectmode);
984                         ED_view3d_backbuf_validate(vc);
985                         BMFace *efa_zbuf = NULL;
986                         BMFace *efa_test = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
987                         if (efa_test && dist_center_p) {
988                                 dist = min_ff(dist_margin, dist_center);
989                         }
990                         if (efa_test) {
991                                 hit.f.base_index = base_index;
992                                 hit.f.ele  = efa_test;
993                         }
994                         if (efa_zbuf) {
995                                 hit.f_zbuf.base_index = base_index;
996                                 hit.f_zbuf.ele  = efa_zbuf;
997                         }
998                 } /* bases */
999         }
1000
1001         if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
1002                 float dist_center = 0.0f;
1003                 float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
1004
1005                 for (uint base_index = 0; base_index < bases_len; base_index++) {
1006                         Base *base_iter = bases[base_index];
1007                         Object *obedit = base_iter->object;
1008                         ED_view3d_viewcontext_init_object(vc, obedit);
1009                         ED_view3d_backbuf_validate(vc);
1010                         BMEdge *eed_zbuf = NULL;
1011                         BMEdge *eed_test = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
1012                         if (eed_test && dist_center_p) {
1013                                 dist = min_ff(dist_margin, dist_center);
1014                         }
1015                         if (eed_test) {
1016                                 hit.e.base_index = base_index;
1017                                 hit.e.ele  = eed_test;
1018                         }
1019                         if (eed_zbuf) {
1020                                 hit.e_zbuf.base_index = base_index;
1021                                 hit.e_zbuf.ele  = eed_zbuf;
1022                         }
1023                 } /* bases */
1024         }
1025
1026         if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) {
1027                 for (uint base_index = 0; base_index < bases_len; base_index++) {
1028                         Base *base_iter = bases[base_index];
1029                         Object *obedit = base_iter->object;
1030                         ED_view3d_viewcontext_init_object(vc, obedit);
1031                         ED_view3d_backbuf_validate(vc);
1032                         BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
1033                         if (eve_test) {
1034                                 hit.v.base_index = base_index;
1035                                 hit.v.ele  = eve_test;
1036                         }
1037                 } /* bases */
1038         }
1039
1040         /* return only one of 3 pointers, for frontbuffer redraws */
1041         if (hit.v.ele) {
1042                 hit.f.ele = NULL;
1043                 hit.e.ele = NULL;
1044         }
1045         else if (hit.e.ele) {
1046                 hit.f.ele = NULL;
1047         }
1048
1049         /* there may be a face under the cursor, who's center if too far away
1050          * use this if all else fails, it makes sense to select this */
1051         if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) {
1052                 if (hit.e_zbuf.ele) {
1053                         hit.e.base_index = hit.e_zbuf.base_index;
1054                         hit.e.ele  = hit.e_zbuf.ele;
1055                 }
1056                 else if (hit.f_zbuf.ele) {
1057                         hit.f.base_index = hit.f_zbuf.base_index;
1058                         hit.f.ele  = hit.f_zbuf.ele;
1059                 }
1060         }
1061
1062         mval_prev[0] = vc->mval[0];
1063         mval_prev[1] = vc->mval[1];
1064
1065         /* Only one element type will be non-null. */
1066         BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1);
1067
1068         if (hit.v.ele) {
1069                 *r_base_index = hit.v.base_index;
1070         }
1071         if (hit.e.ele) {
1072                 *r_base_index = hit.e.base_index;
1073         }
1074         if (hit.f.ele) {
1075                 *r_base_index = hit.f.base_index;
1076         }
1077
1078         *r_eve = hit.v.ele;
1079         *r_eed = hit.e.ele;
1080         *r_efa = hit.f.ele;
1081
1082         return (hit.v.ele || hit.e.ele || hit.f.ele);
1083 }
1084
1085 #undef FAKE_SELECT_MODE_BEGIN
1086 #undef FAKE_SELECT_MODE_END
1087
1088 bool EDBM_unified_findnearest(
1089         ViewContext *vc, Base **bases, const uint bases_len,
1090         int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
1091 {
1092         return unified_findnearest(vc, bases, bases_len, r_base_index, r_eve, r_eed, r_efa);
1093 }
1094
1095 /** \} */
1096
1097 /* -------------------------------------------------------------------- */
1098 /** \name Alternate Find Nearest Vert/Edge (optional boundary)
1099  *
1100  * \note This uses ray-cast method instead of backbuffer,
1101  * currently used for poly-build.
1102  * \{ */
1103
1104 bool EDBM_unified_findnearest_from_raycast(
1105         ViewContext *vc,
1106         Base **bases, const uint bases_len,
1107         bool use_boundary,
1108         int *r_base_index,
1109         struct BMVert **r_eve,
1110         struct BMEdge **r_eed,
1111         struct BMFace **r_efa)
1112 {
1113
1114         const float mval_fl[2] = {UNPACK2(vc->mval)};
1115         float ray_origin[3], ray_direction[3];
1116
1117         struct {
1118                 uint base_index;
1119                 BMElem *ele;
1120         } best = {0, NULL};
1121
1122         if (ED_view3d_win_to_ray_clipped(
1123                 vc->depsgraph,
1124                 vc->ar, vc->v3d, mval_fl,
1125                 ray_origin, ray_direction, true))
1126         {
1127                 float dist_sq_best = FLT_MAX;
1128
1129                 const bool use_vert = (r_eve != NULL);
1130                 const bool use_edge = (r_eed != NULL);
1131                 const bool use_face = (r_efa != NULL);
1132
1133                 for (uint base_index = 0; base_index < bases_len; base_index++) {
1134                         Base *base_iter = bases[base_index];
1135                         Object *obedit = base_iter->object;
1136
1137                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1138                         BMesh *bm = em->bm;
1139                         float imat3[3][3];
1140
1141                         ED_view3d_viewcontext_init_object(vc, obedit);
1142                         copy_m3_m4(imat3, obedit->obmat);
1143                         invert_m3(imat3);
1144
1145                         const float (*coords)[3] = NULL;
1146                         {
1147                                 Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data);
1148                                 if (me_eval->runtime.edit_data) {
1149                                         coords = me_eval->runtime.edit_data->vertexCos;
1150                                 }
1151                         }
1152
1153                         if (coords != NULL) {
1154                                 BM_mesh_elem_index_ensure(bm, BM_VERT);
1155                         }
1156
1157                         if (use_boundary && (use_vert || use_edge)) {
1158                                 BMEdge *e;
1159                                 BMIter eiter;
1160                                 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
1161                                         if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) &&
1162                                             (BM_edge_is_boundary(e)))
1163                                         {
1164                                                 float depth;
1165
1166                                                 if (use_vert) {
1167                                                         for (uint j = 0; j < 2; j++) {
1168                                                                 BMVert *v = *((&e->v1) + j);
1169                                                                 float point[3];
1170                                                                 mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
1171                                                                 const float dist_sq_test = dist_squared_to_ray_v3(
1172                                                                         ray_origin, ray_direction,
1173                                                                         point, &depth);
1174                                                                 if (dist_sq_test < dist_sq_best) {
1175                                                                         dist_sq_best = dist_sq_test;
1176                                                                         best.base_index = base_index;
1177                                                                         best.ele = (BMElem *)v;
1178                                                                 }
1179                                                         }
1180                                                 }
1181
1182                                                 if (use_edge) {
1183                                                         float point[3];
1184 #if 0
1185                                                         const float dist_sq_test = dist_squared_ray_to_seg_v3(
1186                                                                 ray_origin, ray_direction,
1187                                                                 e->v1->co,  e->v2->co,
1188                                                                 point, &depth);
1189 #else
1190                                                         if (coords) {
1191                                                                 mid_v3_v3v3(point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
1192                                                         }
1193                                                         else {
1194                                                                 mid_v3_v3v3(point, e->v1->co, e->v2->co);
1195                                                         }
1196                                                         mul_m4_v3(obedit->obmat, point);
1197                                                         const float dist_sq_test = dist_squared_to_ray_v3(
1198                                                                 ray_origin, ray_direction,
1199                                                                 point, &depth);
1200                                                         if (dist_sq_test < dist_sq_best) {
1201                                                                 dist_sq_best = dist_sq_test;
1202                                                                 best.base_index = base_index;
1203                                                                 best.ele = (BMElem *)e;
1204                                                         }
1205 #endif
1206                                                 }
1207                                         }
1208                                 }
1209                         }
1210                         else {
1211                                 /* Non boundary case. */
1212                                 if (use_vert) {
1213                                         BMVert *v;
1214                                         BMIter viter;
1215                                         BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
1216                                                 if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
1217                                                         float point[3];
1218                                                         mul_v3_m4v3(point, obedit->obmat, v->co);
1219                                                         float depth;
1220                                                         const float dist_sq_test = dist_squared_to_ray_v3(
1221                                                                 ray_origin, ray_direction,
1222                                                                 v->co, &depth);
1223                                                         if (dist_sq_test < dist_sq_best) {
1224                                                                 dist_sq_best = dist_sq_test;
1225                                                                 best.base_index = base_index;
1226                                                                 best.ele = (BMElem *)v;
1227                                                         }
1228                                                 }
1229                                         }
1230                                 }
1231                                 if (use_edge) {
1232                                         BMEdge *e;
1233                                         BMIter eiter;
1234                                         BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
1235                                                 if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
1236                                                         float point[3];
1237                                                         if (coords) {
1238                                                                 mid_v3_v3v3(point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
1239                                                         }
1240                                                         else {
1241                                                                 mid_v3_v3v3(point, e->v1->co, e->v2->co);
1242                                                         }
1243                                                         mul_m4_v3(obedit->obmat, point);
1244                                                         float depth;
1245                                                         const float dist_sq_test = dist_squared_to_ray_v3(
1246                                                                 ray_origin, ray_direction,
1247                                                                 point, &depth);
1248                                                         if (dist_sq_test < dist_sq_best) {
1249                                                                 dist_sq_best = dist_sq_test;
1250                                                                 best.base_index = base_index;
1251                                                                 best.ele = (BMElem *)e;
1252                                                         }
1253                                                 }
1254                                         }
1255                                 }
1256                         }
1257
1258                         if (use_face) {
1259                                 BMFace *f;
1260                                 BMIter fiter;
1261                                 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
1262                                         if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == false) {
1263                                                 float point[3];
1264                                                 if (coords) {
1265                                                         BM_face_calc_center_median_vcos(bm, f, point, coords);
1266                                                 }
1267                                                 else {
1268                                                         BM_face_calc_center_median(f, point);
1269                                                 }
1270                                                 mul_m4_v3(obedit->obmat, point);
1271                                                 float depth;
1272                                                 const float dist_sq_test = dist_squared_to_ray_v3(
1273                                                         ray_origin, ray_direction,
1274                                                         point, &depth);
1275                                                 if (dist_sq_test < dist_sq_best) {
1276                                                         dist_sq_best = dist_sq_test;
1277                                                         best.base_index = base_index;
1278                                                         best.ele = (BMElem *)f;
1279                                                 }
1280                                         }
1281                                 }
1282                         }
1283                 }
1284         }
1285
1286         *r_base_index = best.base_index;
1287         if (r_eve) {
1288                 *r_eve = NULL;
1289         }
1290         if (r_eed) {
1291                 *r_eed = NULL;
1292         }
1293         if (r_efa) {
1294                 *r_efa = NULL;
1295         }
1296
1297         if (best.ele) {
1298                 switch (best.ele->head.htype) {
1299                         case BM_VERT:
1300                                 *r_eve = (BMVert *)best.ele;
1301                                 break;
1302                         case BM_EDGE:
1303                                 *r_eed = (BMEdge *)best.ele;
1304                                 break;
1305                         case BM_FACE:
1306                                 *r_efa = (BMFace *)best.ele;
1307                                 break;
1308                         default:
1309                                 BLI_assert(0);
1310                 }
1311         }
1312         return (best.ele != NULL);
1313 }
1314
1315 /** \} */
1316
1317 /* -------------------------------------------------------------------- */
1318 /** \name Select Similar Region Operator
1319  * \{ */
1320
1321 static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
1322 {
1323         Object *obedit = CTX_data_edit_object(C);
1324         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1325         BMesh *bm = em->bm;
1326         bool changed = false;
1327
1328         /* group vars */
1329         int *groups_array;
1330         int (*group_index)[2];
1331         int group_tot;
1332         int i;
1333
1334         if (bm->totfacesel < 2) {
1335                 BKE_report(op->reports, RPT_ERROR, "No face regions selected");
1336                 return OPERATOR_CANCELLED;
1337         }
1338
1339         groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
1340         group_tot = BM_mesh_calc_face_groups(
1341                 bm, groups_array, &group_index,
1342                 NULL, NULL,
1343                 BM_ELEM_SELECT, BM_VERT);
1344
1345         BM_mesh_elem_table_ensure(bm, BM_FACE);
1346
1347         for (i = 0; i < group_tot; i++) {
1348                 ListBase faces_regions;
1349                 int tot;
1350
1351                 const int fg_sta = group_index[i][0];
1352                 const int fg_len = group_index[i][1];
1353                 int j;
1354                 BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__);
1355
1356
1357                 for (j = 0; j < fg_len; j++) {
1358                         fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
1359                 }
1360
1361                 tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions);
1362
1363                 MEM_freeN(fg);
1364
1365                 if (tot) {
1366                         LinkData *link;
1367                         while ((link = BLI_pophead(&faces_regions))) {
1368                                 BMFace *f, **faces = link->data;
1369                                 while ((f = *(faces++))) {
1370                                         BM_face_select_set(bm, f, true);
1371                                 }
1372                                 MEM_freeN(link->data);
1373                                 MEM_freeN(link);
1374
1375                                 changed = true;
1376                         }
1377                 }
1378         }
1379
1380         MEM_freeN(groups_array);
1381         MEM_freeN(group_index);
1382
1383         if (changed) {
1384                 DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
1385                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1386         }
1387         else {
1388                 BKE_report(op->reports, RPT_WARNING, "No matching face regions found");
1389         }
1390
1391         return OPERATOR_FINISHED;
1392 }
1393
1394 void MESH_OT_select_similar_region(wmOperatorType *ot)
1395 {
1396         /* identifiers */
1397         ot->name = "Select Similar Regions";
1398         ot->idname = "MESH_OT_select_similar_region";
1399         ot->description = "Select similar face regions to the current selection";
1400
1401         /* api callbacks */
1402         ot->exec = edbm_select_similar_region_exec;
1403         ot->poll = ED_operator_editmesh;
1404
1405         /* flags */
1406         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1407 }
1408
1409 /** \} */
1410
1411 /* -------------------------------------------------------------------- */
1412 /** \name Select Mode Vert/Edge/Face Operator
1413  * \{ */
1414
1415 static int edbm_select_mode_exec(bContext *C, wmOperator *op)
1416 {
1417         const int type        = RNA_enum_get(op->ptr,    "type");
1418         const int action      = RNA_enum_get(op->ptr,    "action");
1419         const bool use_extend = RNA_boolean_get(op->ptr, "use_extend");
1420         const bool use_expand = RNA_boolean_get(op->ptr, "use_expand");
1421
1422         if (EDBM_selectmode_toggle(C, type, action, use_extend, use_expand)) {
1423                 return OPERATOR_FINISHED;
1424         }
1425         else {
1426                 return OPERATOR_CANCELLED;
1427         }
1428 }
1429
1430 static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1431 {
1432         /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */
1433         if (CTX_wm_space_image(C)) {
1434                 ToolSettings *ts = CTX_data_tool_settings(C);
1435                 if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
1436                         return OPERATOR_PASS_THROUGH;
1437                 }
1438                 /* Bypass when no action is needed. */
1439                 if (!RNA_struct_property_is_set(op->ptr, "type")) {
1440                         return OPERATOR_CANCELLED;
1441                 }
1442         }
1443
1444         /* detecting these options based on shift/ctrl here is weak, but it's done
1445          * to make this work when clicking buttons or menus */
1446         if (!RNA_struct_property_is_set(op->ptr, "use_extend"))
1447                 RNA_boolean_set(op->ptr, "use_extend", event->shift);
1448         if (!RNA_struct_property_is_set(op->ptr, "use_expand"))
1449                 RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
1450
1451         return edbm_select_mode_exec(C, op);
1452 }
1453
1454 void MESH_OT_select_mode(wmOperatorType *ot)
1455 {
1456         PropertyRNA *prop;
1457
1458         static const EnumPropertyItem elem_items[] = {
1459                 {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""},
1460                 {SCE_SELECT_EDGE,   "EDGE", ICON_EDGESEL, "Edges", ""},
1461                 {SCE_SELECT_FACE,   "FACE", ICON_FACESEL, "Faces", ""},
1462                 {0, NULL, 0, NULL, NULL},
1463         };
1464
1465         static const EnumPropertyItem actions_items[] = {
1466                 {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1467                 {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1468                 {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1469                 {0, NULL, 0, NULL, NULL}
1470         };
1471
1472         /* identifiers */
1473         ot->name = "Select Mode";
1474         ot->idname = "MESH_OT_select_mode";
1475         ot->description = "Change selection mode";
1476
1477         /* api callbacks */
1478         ot->invoke = edbm_select_mode_invoke;
1479         ot->exec = edbm_select_mode_exec;
1480         ot->poll = ED_operator_editmesh;
1481
1482         /* flags */
1483         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1484
1485         /* properties */
1486         /* Hide all, not to show redo panel. */
1487         prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", "");
1488         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1489         prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", "");
1490         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1491         ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", "");
1492         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1493
1494         prop = RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
1495         RNA_def_property_flag(prop, PROP_HIDDEN);
1496 }
1497
1498 /** \} */
1499
1500 /* -------------------------------------------------------------------- */
1501 /** \name Select Loop (Non Modal) Operator
1502  * \{ */
1503
1504 static void walker_select_count(
1505         BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix,
1506         int *r_totsel, int *r_totunsel)
1507 {
1508         BMesh *bm = em->bm;
1509         BMElem *ele;
1510         BMWalker walker;
1511         int tot[2] = {0, 0};
1512
1513         BMW_init(&walker, bm, walkercode,
1514                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
1515                  BMW_FLAG_TEST_HIDDEN,
1516                  BMW_NIL_LAY);
1517
1518         for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1519                 tot[(BM_elem_flag_test_bool(ele, BM_ELEM_SELECT) != select)] += 1;
1520
1521                 if (!select_mix && tot[0] && tot[1]) {
1522                         tot[0] = tot[1] = -1;
1523                         break;
1524                 }
1525         }
1526
1527         *r_totsel = tot[0];
1528         *r_totunsel = tot[1];
1529
1530         BMW_end(&walker);
1531 }
1532
1533 static void walker_select(BMEditMesh *em, int walkercode, void *start, const bool select)
1534 {
1535         BMesh *bm = em->bm;
1536         BMElem *ele;
1537         BMWalker walker;
1538
1539         BMW_init(&walker, bm, walkercode,
1540                  BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
1541                  BMW_FLAG_TEST_HIDDEN,
1542                  BMW_NIL_LAY);
1543
1544         for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
1545                 if (!select) {
1546                         BM_select_history_remove(bm, ele);
1547                 }
1548                 BM_elem_select_set(bm, ele, select);
1549         }
1550         BMW_end(&walker);
1551 }
1552
1553 static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
1554 {
1555         const bool is_ring = RNA_boolean_get(op->ptr, "ring");
1556         ViewLayer *view_layer = CTX_data_view_layer(C);
1557         uint objects_len = 0;
1558         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
1559         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1560                 Object *obedit = objects[ob_index];
1561                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1562
1563                 if (em->bm->totedgesel == 0) {
1564                         continue;
1565                 }
1566
1567                 BMEdge *eed;
1568                 BMEdge **edarray;
1569                 int edindex;
1570                 BMIter iter;
1571                 int totedgesel = 0;
1572
1573                 BM_ITER_MESH(eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1574                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1575                                 totedgesel++;
1576                         }
1577                 }
1578
1579                 edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
1580                 edindex = 0;
1581
1582                 BM_ITER_MESH(eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1583                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
1584                                 edarray[edindex] = eed;
1585                                 edindex++;
1586                         }
1587                 }
1588
1589                 if (is_ring) {
1590                         for (edindex = 0; edindex < totedgesel; edindex += 1) {
1591                                 eed = edarray[edindex];
1592                                 walker_select(em, BMW_EDGERING, eed, true);
1593                         }
1594                         EDBM_selectmode_flush(em);
1595                 }
1596                 else {
1597                         for (edindex = 0; edindex < totedgesel; edindex += 1) {
1598                                 eed = edarray[edindex];
1599                                 walker_select(em, BMW_EDGELOOP, eed, true);
1600                         }
1601                         EDBM_selectmode_flush(em);
1602                 }
1603                 MEM_freeN(edarray);
1604                 //      if (EM_texFaceCheck())
1605
1606                 DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
1607                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1608         }
1609         MEM_freeN(objects);
1610
1611         return OPERATOR_FINISHED;
1612 }
1613
1614 void MESH_OT_loop_multi_select(wmOperatorType *ot)
1615 {
1616         /* identifiers */
1617         ot->name = "Multi Select Loops";
1618         ot->idname = "MESH_OT_loop_multi_select";
1619         ot->description = "Select a loop of connected edges by connection type";
1620
1621         /* api callbacks */
1622         ot->exec = edbm_loop_multiselect_exec;
1623         ot->poll = ED_operator_editmesh;
1624
1625         /* flags */
1626         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1627
1628         /* properties */
1629         RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
1630 }
1631
1632 /** \} */
1633
1634 /* -------------------------------------------------------------------- */
1635 /** \name Select Loop (Cursor Pick) Operator
1636  * \{ */
1637
1638 static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1639 {
1640         if (select_clear) {
1641                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1642         }
1643
1644         walker_select(em, BMW_FACELOOP, eed, select);
1645 }
1646
1647 static void mouse_mesh_loop_edge_ring(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
1648 {
1649         if (select_clear) {
1650                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1651         }
1652
1653         walker_select(em, BMW_EDGERING, eed, select);
1654 }
1655
1656 static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear, bool select_cycle)
1657 {
1658         bool edge_boundary = false;
1659
1660         /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY  */
1661         if (select_cycle && BM_edge_is_boundary(eed)) {
1662                 int tot[2];
1663
1664                 /* if the loops selected toggle the boundaries */
1665                 walker_select_count(em, BMW_EDGELOOP, eed, select, false,
1666                                     &tot[0], &tot[1]);
1667                 if (tot[select] == 0) {
1668                         edge_boundary = true;
1669
1670                         /* if the boundaries selected, toggle back to the loop */
1671                         walker_select_count(em, BMW_EDGEBOUNDARY, eed, select, false,
1672                                             &tot[0], &tot[1]);
1673                         if (tot[select] == 0) {
1674                                 edge_boundary = false;
1675                         }
1676                 }
1677         }
1678
1679         if (select_clear) {
1680                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1681         }
1682
1683         if (edge_boundary) {
1684                 walker_select(em, BMW_EDGEBOUNDARY, eed, select);
1685         }
1686         else {
1687                 walker_select(em, BMW_EDGELOOP, eed, select);
1688         }
1689 }
1690
1691 static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
1692 {
1693         Base *basact = NULL;
1694         BMVert *eve = NULL;
1695         BMEdge *eed = NULL;
1696         BMFace *efa = NULL;
1697
1698         ViewContext vc;
1699         BMEditMesh *em;
1700         bool select = true;
1701         bool select_clear = false;
1702         bool select_cycle = true;
1703         float mvalf[2];
1704
1705         em_setup_viewcontext(C, &vc);
1706         mvalf[0] = (float)(vc.mval[0] = mval[0]);
1707         mvalf[1] = (float)(vc.mval[1] = mval[1]);
1708
1709         BMEditMesh *em_original = vc.em;
1710         const short selectmode = em_original->selectmode;
1711         em_original->selectmode = SCE_SELECT_EDGE;
1712
1713         uint bases_len;
1714         Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
1715
1716         {
1717                 int base_index = -1;
1718                 if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) {
1719                         basact = bases[base_index];
1720                         ED_view3d_viewcontext_init_object(&vc, basact->object);
1721                         em = vc.em;
1722                 }
1723                 else {
1724                         em = NULL;
1725                 }
1726         }
1727
1728         em_original->selectmode = selectmode;
1729
1730         if (em == NULL || eed == NULL) {
1731                 MEM_freeN(bases);
1732                 return false;
1733         }
1734
1735         if (extend == false && deselect == false && toggle == false) {
1736                 select_clear = true;
1737         }
1738
1739         if (extend) {
1740                 select = true;
1741         }
1742         else if (deselect) {
1743                 select = false;
1744         }
1745         else if (select_clear || (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0)) {
1746                 select = true;
1747         }
1748         else if (toggle) {
1749                 select = false;
1750                 select_cycle = false;
1751         }
1752
1753         if (select_clear) {
1754                 for (uint base_index = 0; base_index < bases_len; base_index++) {
1755                         Base *base_iter = bases[base_index];
1756                         Object *ob_iter = base_iter->object;
1757                         BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
1758
1759                         if (em_iter->bm->totvertsel == 0) {
1760                                 continue;
1761                         }
1762
1763                         if (em_iter == em) {
1764                                 continue;
1765                         }
1766
1767                         EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT);
1768                         DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
1769                 }
1770         }
1771
1772         if (em->selectmode & SCE_SELECT_FACE) {
1773                 mouse_mesh_loop_face(em, eed, select, select_clear);
1774         }
1775         else {
1776                 if (ring) {
1777                         mouse_mesh_loop_edge_ring(em, eed, select, select_clear);
1778                 }
1779                 else {
1780                         mouse_mesh_loop_edge(em, eed, select, select_clear, select_cycle);
1781                 }
1782         }
1783
1784         EDBM_selectmode_flush(em);
1785
1786         /* sets as active, useful for other tools */
1787         if (select) {
1788                 if (em->selectmode & SCE_SELECT_VERTEX) {
1789                         /* Find nearest vert from mouse
1790                          * (initialize to large values incase only one vertex can be projected) */
1791                         float v1_co[2], v2_co[2];
1792                         float length_1 = FLT_MAX;
1793                         float length_2 = FLT_MAX;
1794
1795                         /* We can't be sure this has already been set... */
1796                         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1797
1798                         if (ED_view3d_project_float_object(
1799                                     vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1800                         {
1801                                 length_1 = len_squared_v2v2(mvalf, v1_co);
1802                         }
1803
1804                         if (ED_view3d_project_float_object(
1805                                     vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1806                         {
1807                                 length_2 = len_squared_v2v2(mvalf, v2_co);
1808                         }
1809 #if 0
1810                         printf("mouse to v1: %f\nmouse to v2: %f\n", len_squared_v2v2(mvalf, v1_co),
1811                                len_squared_v2v2(mvalf, v2_co));
1812 #endif
1813                         BM_select_history_store(em->bm, (length_1 < length_2) ? eed->v1 : eed->v2);
1814                 }
1815                 else if (em->selectmode & SCE_SELECT_EDGE) {
1816                         BM_select_history_store(em->bm, eed);
1817                 }
1818                 else if (em->selectmode & SCE_SELECT_FACE) {
1819                         /* Select the face of eed which is the nearest of mouse. */
1820                         BMFace *f;
1821                         BMIter iterf;
1822                         float best_dist = FLT_MAX;
1823                         efa = NULL;
1824
1825                         /* We can't be sure this has already been set... */
1826                         ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
1827
1828                         BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) {
1829                                 if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
1830                                         float cent[3];
1831                                         float co[2], tdist;
1832
1833                                         BM_face_calc_center_median(f, cent);
1834                                         if (ED_view3d_project_float_object(
1835                                                     vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1836                                         {
1837                                                 tdist = len_squared_v2v2(mvalf, co);
1838                                                 if (tdist < best_dist) {
1839 /*                                                      printf("Best face: %p (%f)\n", f, tdist);*/
1840                                                         best_dist = tdist;
1841                                                         efa = f;
1842                                                 }
1843                                         }
1844                                 }
1845                         }
1846                         if (efa) {
1847                                 BM_mesh_active_face_set(em->bm, efa);
1848                                 BM_select_history_store(em->bm, efa);
1849                         }
1850                 }
1851         }
1852
1853         MEM_freeN(bases);
1854
1855         DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
1856         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
1857
1858         return true;
1859 }
1860
1861 static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1862 {
1863
1864         view3d_operator_needs_opengl(C);
1865
1866         if (mouse_mesh_loop(
1867                     C, event->mval,
1868                     RNA_boolean_get(op->ptr, "extend"),
1869                     RNA_boolean_get(op->ptr, "deselect"),
1870                     RNA_boolean_get(op->ptr, "toggle"),
1871                     RNA_boolean_get(op->ptr, "ring")))
1872         {
1873                 return OPERATOR_FINISHED;
1874         }
1875         else {
1876                 return OPERATOR_CANCELLED;
1877         }
1878 }
1879
1880 void MESH_OT_loop_select(wmOperatorType *ot)
1881 {
1882         /* identifiers */
1883         ot->name = "Loop Select";
1884         ot->idname = "MESH_OT_loop_select";
1885         ot->description = "Select a loop of connected edges";
1886
1887         /* api callbacks */
1888         ot->invoke = edbm_select_loop_invoke;
1889         ot->poll = ED_operator_editmesh_region_view3d;
1890
1891         /* flags */
1892         ot->flag = OPTYPE_UNDO;
1893
1894         /* properties */
1895         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
1896         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1897         RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1898         RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
1899 }
1900
1901 void MESH_OT_edgering_select(wmOperatorType *ot)
1902 {
1903         /* description */
1904         ot->name = "Edge Ring Select";
1905         ot->idname = "MESH_OT_edgering_select";
1906         ot->description = "Select an edge ring";
1907
1908         /* callbacks */
1909         ot->invoke = edbm_select_loop_invoke;
1910         ot->poll = ED_operator_editmesh_region_view3d;
1911
1912         /* flags */
1913         ot->flag = OPTYPE_UNDO;
1914
1915         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1916         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
1917         RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Select", "Toggle the selection");
1918         RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
1919 }
1920
1921 /** \} */
1922
1923 /* -------------------------------------------------------------------- */
1924 /** \name (De)Select All Operator
1925  * \{ */
1926
1927 static int edbm_select_all_exec(bContext *C, wmOperator *op)
1928 {
1929         ViewLayer *view_layer = CTX_data_view_layer(C);
1930         int action = RNA_enum_get(op->ptr, "action");
1931
1932         uint objects_len = 0;
1933         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
1934
1935         if (action == SEL_TOGGLE) {
1936                 action = SEL_SELECT;
1937                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1938                         Object *obedit = objects[ob_index];
1939                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1940                         if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) {
1941                                 action = SEL_DESELECT;
1942                                 break;
1943                         }
1944                 }
1945         }
1946
1947         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1948                 Object *obedit = objects[ob_index];
1949                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1950                 switch (action) {
1951                         case SEL_SELECT:
1952                                 EDBM_flag_enable_all(em, BM_ELEM_SELECT);
1953                                 break;
1954                         case SEL_DESELECT:
1955                                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1956                                 break;
1957                         case SEL_INVERT:
1958                                 EDBM_select_swap(em);
1959                                 EDBM_selectmode_flush(em);
1960                                 break;
1961                 }
1962                 DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
1963                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1964         }
1965
1966         MEM_freeN(objects);
1967
1968         return OPERATOR_FINISHED;
1969 }
1970
1971 void MESH_OT_select_all(wmOperatorType *ot)
1972 {
1973         /* identifiers */
1974         ot->name = "(De)select All";
1975         ot->idname = "MESH_OT_select_all";
1976         ot->description = "(De)select all vertices, edges or faces";
1977
1978         /* api callbacks */
1979         ot->exec = edbm_select_all_exec;
1980         ot->poll = ED_operator_editmesh;
1981
1982         /* flags */
1983         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1984
1985         WM_operator_properties_select_all(ot);
1986 }
1987
1988 /** \} */
1989
1990 /* -------------------------------------------------------------------- */
1991 /** \name Select Interior Faces Operator
1992  * \{ */
1993
1994 static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
1995 {
1996         ViewLayer *view_layer = CTX_data_view_layer(C);
1997         uint objects_len = 0;
1998         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
1999
2000         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2001                 Object *obedit = objects[ob_index];
2002                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2003
2004                 if (!EDBM_select_interior_faces(em)) {
2005                         continue;
2006                 }
2007
2008                 DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
2009                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2010         }
2011         MEM_freeN(objects);
2012
2013         return OPERATOR_FINISHED;
2014 }
2015
2016 void MESH_OT_select_interior_faces(wmOperatorType *ot)
2017 {
2018         /* identifiers */
2019         ot->name = "Select Interior Faces";
2020         ot->idname = "MESH_OT_select_interior_faces";
2021         ot->description = "Select faces where all edges have more than 2 face users";
2022
2023         /* api callbacks */
2024         ot->exec = edbm_faces_select_interior_exec;
2025         ot->poll = ED_operator_editmesh;
2026
2027         /* flags */
2028         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2029 }
2030
2031 /** \} */
2032
2033 /* -------------------------------------------------------------------- */
2034 /** \name Select Picking API
2035  *
2036  * Here actual select happens,
2037  * Gets called via generic mouse select operator.
2038  * \{ */
2039
2040 bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
2041 {
2042         ViewContext vc;
2043
2044         int base_index_active = -1;
2045         BMVert *eve = NULL;
2046         BMEdge *eed = NULL;
2047         BMFace *efa = NULL;
2048
2049         /* setup view context for argument to callbacks */
2050         em_setup_viewcontext(C, &vc);
2051         vc.mval[0] = mval[0];
2052         vc.mval[1] = mval[1];
2053
2054         uint bases_len = 0;
2055         Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
2056
2057         bool ok = false;
2058
2059         if (unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa)) {
2060                 Base *basact = bases[base_index_active];
2061                 ED_view3d_viewcontext_init_object(&vc, basact->object);
2062
2063                 /* Deselect everything */
2064                 if (extend == false && deselect == false && toggle == false) {
2065                         for (uint base_index = 0; base_index < bases_len; base_index++) {
2066                                 Base *base_iter = bases[base_index];
2067                                 Object *ob_iter = base_iter->object;
2068                                 EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT);
2069                                 if (basact->object != ob_iter) {
2070                                         DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
2071                                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
2072                                 }
2073                         }
2074                 }
2075
2076                 if (efa) {
2077                         if (extend) {
2078                                 /* set the last selected face */
2079                                 BM_mesh_active_face_set(vc.em->bm, efa);
2080
2081                                 /* Work-around: deselect first, so we can guarantee it will */
2082                                 /* be active even if it was already selected */
2083                                 BM_select_history_remove(vc.em->bm, efa);
2084                                 BM_face_select_set(vc.em->bm, efa, false);
2085                                 BM_select_history_store(vc.em->bm, efa);
2086                                 BM_face_select_set(vc.em->bm, efa, true);
2087                         }
2088                         else if (deselect) {
2089                                 BM_select_history_remove(vc.em->bm, efa);
2090                                 BM_face_select_set(vc.em->bm, efa, false);
2091                         }
2092                         else {
2093                                 /* set the last selected face */
2094                                 BM_mesh_active_face_set(vc.em->bm, efa);
2095
2096                                 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2097                                         BM_select_history_store(vc.em->bm, efa);
2098                                         BM_face_select_set(vc.em->bm, efa, true);
2099                                 }
2100                                 else if (toggle) {
2101                                         BM_select_history_remove(vc.em->bm, efa);
2102                                         BM_face_select_set(vc.em->bm, efa, false);
2103                                 }
2104                         }
2105                 }
2106                 else if (eed) {
2107                         if (extend) {
2108                                 /* Work-around: deselect first, so we can guarantee it will */
2109                                 /* be active even if it was already selected */
2110                                 BM_select_history_remove(vc.em->bm, eed);
2111                                 BM_edge_select_set(vc.em->bm, eed, false);
2112                                 BM_select_history_store(vc.em->bm, eed);
2113                                 BM_edge_select_set(vc.em->bm, eed, true);
2114                         }
2115                         else if (deselect) {
2116                                 BM_select_history_remove(vc.em->bm, eed);
2117                                 BM_edge_select_set(vc.em->bm, eed, false);
2118                         }
2119                         else {
2120                                 if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2121                                         BM_select_history_store(vc.em->bm, eed);
2122                                         BM_edge_select_set(vc.em->bm, eed, true);
2123                                 }
2124                                 else if (toggle) {
2125                                         BM_select_history_remove(vc.em->bm, eed);
2126                                         BM_edge_select_set(vc.em->bm, eed, false);
2127                                 }
2128                         }
2129                 }
2130                 else if (eve) {
2131                         if (extend) {
2132                                 /* Work-around: deselect first, so we can guarantee it will */
2133                                 /* be active even if it was already selected */
2134                                 BM_select_history_remove(vc.em->bm, eve);
2135                                 BM_vert_select_set(vc.em->bm, eve, false);
2136                                 BM_select_history_store(vc.em->bm, eve);
2137                                 BM_vert_select_set(vc.em->bm, eve, true);
2138                         }
2139                         else if (deselect) {
2140                                 BM_select_history_remove(vc.em->bm, eve);
2141                                 BM_vert_select_set(vc.em->bm, eve, false);
2142                         }
2143                         else {
2144                                 if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
2145                                         BM_select_history_store(vc.em->bm, eve);
2146                                         BM_vert_select_set(vc.em->bm, eve, true);
2147                                 }
2148                                 else if (toggle) {
2149                                         BM_select_history_remove(vc.em->bm, eve);
2150                                         BM_vert_select_set(vc.em->bm, eve, false);
2151                                 }
2152                         }
2153                 }
2154
2155                 EDBM_selectmode_flush(vc.em);
2156
2157                 if (efa) {
2158                         /* Change active material on object. */
2159                         if (efa->mat_nr != vc.obedit->actcol - 1) {
2160                                 vc.obedit->actcol = efa->mat_nr + 1;
2161                                 vc.em->mat_nr = efa->mat_nr;
2162                                 WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
2163                         }
2164
2165                         /* Change active face-map on object. */
2166                         if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) {
2167                                 const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP);
2168                                 if (cd_fmap_offset != -1) {
2169                                         int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset));
2170                                         if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) {
2171                                                 map = -1;
2172                                         }
2173                                         map += 1;
2174                                         if (map != vc.obedit->actfmap) {
2175                                                 /* We may want to add notifiers later,
2176                                                  * currently select update handles redraw. */
2177                                                 vc.obedit->actfmap = map;
2178                                         }
2179                                 }
2180                         }
2181
2182                 }
2183
2184                 /* Changing active object is handy since it allows us to
2185                  * switch UV layers, vgroups for eg. */
2186                 if (vc.view_layer->basact != basact) {
2187                         ED_object_base_activate(C, basact);
2188                 }
2189
2190                 DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
2191                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2192
2193                 ok = true;
2194         }
2195
2196         MEM_freeN(bases);
2197
2198         return ok;
2199 }
2200
2201 /** \} */
2202
2203 /* -------------------------------------------------------------------- */
2204 /** \name Select Mode Utilities
2205  * \{ */
2206
2207 static void edbm_strip_selections(BMEditMesh *em)
2208 {
2209         BMEditSelection *ese, *nextese;
2210
2211         if (!(em->selectmode & SCE_SELECT_VERTEX)) {
2212                 ese = em->bm->selected.first;
2213                 while (ese) {
2214                         nextese = ese->next;
2215                         if (ese->htype == BM_VERT) BLI_freelinkN(&(em->bm->selected), ese);
2216                         ese = nextese;
2217                 }
2218         }
2219         if (!(em->selectmode & SCE_SELECT_EDGE)) {
2220                 ese = em->bm->selected.first;
2221                 while (ese) {
2222                         nextese = ese->next;
2223                         if (ese->htype == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
2224                         ese = nextese;
2225                 }
2226         }
2227         if (!(em->selectmode & SCE_SELECT_FACE)) {
2228                 ese = em->bm->selected.first;
2229                 while (ese) {
2230                         nextese = ese->next;
2231                         if (ese->htype == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
2232                         ese = nextese;
2233                 }
2234         }
2235 }
2236
2237 /* when switching select mode, makes sure selection is consistent for editing */
2238 /* also for paranoia checks to make sure edge or face mode works */
2239 void EDBM_selectmode_set(BMEditMesh *em)
2240 {
2241         BMVert *eve;
2242         BMEdge *eed;
2243         BMFace *efa;
2244         BMIter iter;
2245
2246         em->bm->selectmode = em->selectmode;
2247
2248         edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */
2249
2250         if (em->bm->totvertsel == 0 &&
2251             em->bm->totedgesel == 0 &&
2252             em->bm->totfacesel == 0)
2253         {
2254                 return;
2255         }
2256
2257         if (em->selectmode & SCE_SELECT_VERTEX) {
2258                 if (em->bm->totvertsel) {
2259                         EDBM_select_flush(em);
2260                 }
2261         }
2262         else if (em->selectmode & SCE_SELECT_EDGE) {
2263                 /* deselect vertices, and select again based on edge select */
2264                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2265                         BM_vert_select_set(em->bm, eve, false);
2266                 }
2267
2268                 if (em->bm->totedgesel) {
2269                         BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2270                                 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
2271                                         BM_edge_select_set(em->bm, eed, true);
2272                                 }
2273                         }
2274
2275                         /* selects faces based on edge status */
2276                         EDBM_selectmode_flush(em);
2277                 }
2278         }
2279         else if (em->selectmode & SCE_SELECT_FACE) {
2280                 /* deselect eges, and select again based on face select */
2281                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2282                         BM_edge_select_set(em->bm, eed, false);
2283                 }
2284
2285                 if (em->bm->totfacesel) {
2286                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2287                                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2288                                         BM_face_select_set(em->bm, efa, true);
2289                                 }
2290                         }
2291                 }
2292         }
2293 }
2294
2295 /**
2296  * Expand & Contract the Selection
2297  * (used when changing modes and Ctrl key held)
2298  *
2299  * Flush the selection up:
2300  * - vert -> edge
2301  * - vert -> face
2302  * - edge -> face
2303  *
2304  * Flush the selection down:
2305  * - face -> edge
2306  * - face -> vert
2307  * - edge -> vert
2308  */
2309 void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new)
2310 {
2311         BMesh *bm = em->bm;
2312
2313         BMVert *eve;
2314         BMEdge *eed;
2315         BMFace *efa;
2316         BMIter iter;
2317
2318         /* first tag-to-select, then select --- this avoids a feedback loop */
2319
2320         /* have to find out what the selectionmode was previously */
2321         if (selectmode_old == SCE_SELECT_VERTEX) {
2322                 if (bm->totvertsel == 0) {
2323                         /* pass */
2324                 }
2325                 else if (selectmode_new == SCE_SELECT_EDGE) {
2326                         /* flush up (vert -> edge) */
2327
2328                         /* select all edges associated with every selected vert */
2329                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2330                                 BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT));
2331                         }
2332
2333                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2334                                 if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
2335                                         BM_edge_select_set(bm, eed, true);
2336                                 }
2337                         }
2338                 }
2339                 else if (selectmode_new == SCE_SELECT_FACE) {
2340                         /* flush up (vert -> face) */
2341
2342                         /* select all faces associated with every selected vert */
2343                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2344                                 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_vert_flag_test(efa, BM_ELEM_SELECT));
2345                         }
2346
2347                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2348                                 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2349                                         BM_face_select_set(bm, efa, true);
2350                                 }
2351                         }
2352                 }
2353         }
2354         else if (selectmode_old == SCE_SELECT_EDGE) {
2355                 if (bm->totedgesel == 0) {
2356                         /* pass */
2357                 }
2358                 else if (selectmode_new == SCE_SELECT_FACE) {
2359                         /* flush up (edge -> face) */
2360
2361                         /* select all faces associated with every selected edge */
2362                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2363                                 BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT));
2364                         }
2365
2366                         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2367                                 if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2368                                         BM_face_select_set(bm, efa, true);
2369                                 }
2370                         }
2371                 }
2372                 else if (selectmode_new == SCE_SELECT_VERTEX) {
2373                         /* flush down (edge -> vert) */
2374
2375                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2376                                 if (!BM_vert_is_all_edge_flag_test(eve, BM_ELEM_SELECT, true)) {
2377                                         BM_vert_select_set(bm, eve, false);
2378                                 }
2379                         }
2380                         /* deselect edges without both verts selected */
2381                         BM_mesh_deselect_flush(bm);
2382                 }
2383         }
2384         else if (selectmode_old == SCE_SELECT_FACE) {
2385                 if (bm->totfacesel == 0) {
2386                         /* pass */
2387                 }
2388                 else if (selectmode_new == SCE_SELECT_EDGE) {
2389                         /* flush down (face -> edge) */
2390
2391                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
2392                                 if (!BM_edge_is_all_face_flag_test(eed, BM_ELEM_SELECT, true)) {
2393                                         BM_edge_select_set(bm, eed, false);
2394                                 }
2395                         }
2396                 }
2397                 else if (selectmode_new == SCE_SELECT_VERTEX) {
2398                         /* flush down (face -> vert) */
2399
2400                         BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
2401                                 if (!BM_vert_is_all_face_flag_test(eve, BM_ELEM_SELECT, true)) {
2402                                         BM_vert_select_set(bm, eve, false);
2403                                 }
2404                         }
2405                         /* deselect faces without verts selected */
2406                         BM_mesh_deselect_flush(bm);
2407                 }
2408         }
2409 }
2410
2411 /* user facing function, does notification */
2412 bool EDBM_selectmode_toggle(
2413         bContext *C, const short selectmode_new,
2414         const int action, const bool use_extend, const bool use_expand)
2415 {
2416         Scene *scene = CTX_data_scene(C);
2417         ViewLayer *view_layer = CTX_data_view_layer(C);
2418         ToolSettings *ts = CTX_data_tool_settings(C);
2419         Object *obedit = CTX_data_edit_object(C);
2420         BMEditMesh *em = NULL;
2421         bool ret = false;
2422
2423         if (obedit && obedit->type == OB_MESH) {
2424                 em = BKE_editmesh_from_object(obedit);
2425         }
2426
2427         if (em == NULL) {
2428                 return ret;
2429         }
2430
2431         bool only_update = false;
2432         switch (action) {
2433                 case -1:
2434                         /* already set */
2435                         break;
2436                 case 0:  /* disable */
2437                         /* check we have something to do */
2438                         if ((em->selectmode & selectmode_new) == 0) {
2439                                 only_update = true;
2440                                 break;
2441                         }
2442                         em->selectmode &= ~selectmode_new;
2443                         break;
2444                 case 1:  /* enable */
2445                         /* check we have something to do */
2446                         if ((em->selectmode & selectmode_new) != 0) {
2447                                 only_update = true;
2448                                 break;
2449                         }
2450                         em->selectmode |= selectmode_new;
2451                         break;
2452                 case 2:  /* toggle */
2453                         /* can't disable this flag if its the only one set */
2454                         if (em->selectmode == selectmode_new) {
2455                                 only_update = true;
2456                                 break;
2457                         }
2458                         em->selectmode ^= selectmode_new;
2459                         break;
2460                 default:
2461                         BLI_assert(0);
2462                         break;
2463         }
2464
2465         uint objects_len = 0;
2466         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
2467
2468         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2469                 Object *ob_iter = objects[ob_index];
2470                 BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2471                 if (em_iter != em) {
2472                         em_iter->selectmode = em->selectmode;
2473                 }
2474         }
2475
2476         if (only_update) {
2477                 MEM_freeN(objects);
2478                 return false;
2479         }
2480
2481         if (use_extend == 0 || em->selectmode == 0) {
2482                 if (use_expand) {
2483                         const short selmode_max = highest_order_bit_s(ts->selectmode);
2484                         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2485                                 Object *ob_iter = objects[ob_index];
2486                                 BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2487                                 EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new);
2488                         }
2489                 }
2490         }
2491
2492         switch (selectmode_new) {
2493                 case SCE_SELECT_VERTEX:
2494                         if (use_extend == 0 || em->selectmode == 0) {
2495                                 em->selectmode = SCE_SELECT_VERTEX;
2496                         }
2497                         ret = true;
2498                         break;
2499                 case SCE_SELECT_EDGE:
2500                         if (use_extend == 0 || em->selectmode == 0) {
2501                                 em->selectmode = SCE_SELECT_EDGE;
2502                         }
2503                         ret = true;
2504                         break;
2505                 case SCE_SELECT_FACE:
2506                         if (use_extend == 0 || em->selectmode == 0) {
2507                                 em->selectmode = SCE_SELECT_FACE;
2508                         }
2509                         ret = true;
2510                         break;
2511                 default:
2512                         BLI_assert(0);
2513                         break;
2514         }
2515
2516         if (ret == true) {
2517                 ts->selectmode = em->selectmode;
2518                 em = NULL;
2519                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2520                         Object *ob_iter = objects[ob_index];
2521                         BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
2522                         em_iter->selectmode = ts->selectmode;
2523                         EDBM_selectmode_set(em_iter);
2524                         DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
2525                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
2526                 }
2527                 WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
2528                 DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
2529         }
2530
2531         MEM_freeN(objects);
2532         return ret;
2533 }
2534
2535 /**
2536  * Use to disable a selectmode if its enabled, Using another mode as a fallback
2537  * if the disabled mode is the only mode set.
2538  *
2539  * \return true if the mode is changed.
2540  */
2541 bool EDBM_selectmode_disable(
2542         Scene *scene, BMEditMesh *em,
2543         const short selectmode_disable,
2544         const short selectmode_fallback)
2545 {
2546         /* note essential, but switch out of vertex mode since the
2547          * selected regions wont be nicely isolated after flushing */
2548         if (em->selectmode & selectmode_disable) {
2549                 if (em->selectmode == selectmode_disable) {
2550                         em->selectmode = selectmode_fallback;
2551                 }
2552                 else {
2553                         em->selectmode &= ~selectmode_disable;
2554                 }
2555                 scene->toolsettings->selectmode = em->selectmode;
2556                 EDBM_selectmode_set(em);
2557
2558                 WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene);
2559
2560                 return true;
2561         }
2562         else {
2563                 return false;
2564         }
2565 }
2566
2567 /** \} */
2568
2569 /* -------------------------------------------------------------------- */
2570 /** \name Select Toggle
2571  * \{ */
2572
2573 bool EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select)
2574 {
2575         BMIter iter;
2576         BMFace *efa;
2577         bool changed = false;
2578
2579         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2580                 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2581                         continue;
2582                 if (efa->mat_nr == index) {
2583                         changed = true;
2584                         BM_face_select_set(em->bm, efa, select);
2585                 }
2586         }
2587         return changed;
2588 }
2589
2590 void EDBM_select_toggle_all(BMEditMesh *em) /* exported for UV */
2591 {
2592         if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
2593                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2594         else
2595                 EDBM_flag_enable_all(em, BM_ELEM_SELECT);
2596 }
2597
2598 void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
2599 {
2600         BMIter iter;
2601         BMVert *eve;
2602         BMEdge *eed;
2603         BMFace *efa;
2604
2605         if (em->bm->selectmode & SCE_SELECT_VERTEX) {
2606                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2607                         if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
2608                                 continue;
2609                         BM_vert_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT));
2610                 }
2611         }
2612         else if (em->selectmode & SCE_SELECT_EDGE) {
2613                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
2614                         if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
2615                                 continue;
2616                         BM_edge_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT));
2617                 }
2618         }
2619         else {
2620                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2621                         if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2622                                 continue;
2623                         BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT));
2624                 }
2625
2626         }
2627 }
2628
2629 /** \} */
2630
2631 /* -------------------------------------------------------------------- */
2632 /** \name Select Interior Faces
2633  *
2634  * \note This algorithm is limited to single faces and could be improved, see:
2635  * https://blender.stackexchange.com/questions/18916
2636  * \{ */
2637
2638 bool EDBM_select_interior_faces(BMEditMesh *em)
2639 {
2640         BMesh *bm = em->bm;
2641         BMIter iter;
2642         BMIter eiter;
2643         BMFace *efa;
2644         BMEdge *eed;
2645         bool ok;
2646         bool changed = false;
2647
2648         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2649                 if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
2650                         continue;
2651
2652
2653                 ok = true;
2654                 BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
2655                         if (!BM_edge_face_count_is_over(eed, 2)) {
2656                                 ok = false;
2657                                 break;
2658                         }
2659                 }
2660
2661                 if (ok) {
2662                         BM_face_select_set(bm, efa, true);
2663                         changed = true;
2664                 }
2665         }
2666
2667         return changed;
2668 }
2669
2670 /** \} */
2671
2672 /* -------------------------------------------------------------------- */
2673 /** \name Select Linked Operator
2674  *
2675  * Support delimiting on different edge properties.
2676  * \{ */
2677
2678 /* so we can have last-used default depend on selection mode (rare exception!) */
2679 #define USE_LINKED_SELECT_DEFAULT_HACK
2680
2681 struct DelimitData {
2682         int cd_loop_type;
2683         int cd_loop_offset;
2684 };
2685
2686 static bool select_linked_delimit_test(
2687         BMEdge *e, int delimit,
2688         const struct DelimitData *delimit_data)
2689 {
2690         BLI_assert(delimit);
2691
2692         if (delimit & BMO_DELIM_SEAM) {
2693                 if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
2694                         return true;
2695                 }
2696         }
2697
2698         if (delimit & BMO_DELIM_SHARP) {
2699                 if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
2700                         return true;
2701                 }
2702         }
2703
2704         if (delimit & BMO_DELIM_NORMAL) {
2705                 if (!BM_edge_is_contiguous(e)) {
2706                         return true;
2707                 }
2708         }
2709
2710         if (delimit & BMO_DELIM_MATERIAL) {
2711                 if (e->l && e->l->radial_next != e->l) {
2712                         const short mat_nr = e->l->f->mat_nr;
2713                         BMLoop *l_iter = e->l->radial_next;
2714                         do {
2715                                 if (l_iter->f->mat_nr != mat_nr) {
2716                                         return true;
2717                                 }
2718                         } while ((l_iter = l_iter->radial_next) != e->l);
2719                 }
2720         }
2721
2722         if (delimit & BMO_DELIM_UV) {
2723                 if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) {
2724                         return true;
2725                 }
2726         }
2727
2728         return false;
2729 }
2730
2731 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2732 /**
2733  * Gets the default from the operator fallback to own last-used value
2734  * (selected based on mode)
2735  */
2736 static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode)
2737 {
2738         static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
2739         int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
2740         char *delimit_last = &delimit_last_store[delimit_last_index];
2741         PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit");
2742         int delimit;
2743
2744         if (RNA_property_is_set(op->ptr, prop_delimit)) {
2745                 delimit = RNA_property_enum_get(op->ptr, prop_delimit);
2746                 *delimit_last = delimit;
2747         }
2748         else {
2749                 delimit = *delimit_last;
2750                 RNA_property_enum_set(op->ptr, prop_delimit, delimit);
2751         }
2752         return delimit;
2753 }
2754 #endif
2755
2756 static void select_linked_delimit_validate(BMesh *bm, int *delimit)
2757 {
2758         if ((*delimit) & BMO_DELIM_UV) {
2759                 if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) {
2760                         (*delimit) &= ~BMO_DELIM_UV;
2761                 }
2762         }
2763 }
2764
2765 static void select_linked_delimit_begin(BMesh *bm, int delimit)
2766 {
2767         struct DelimitData delimit_data = {0};
2768
2769         if (delimit & BMO_DELIM_UV) {
2770                 delimit_data.cd_loop_type = CD_MLOOPUV;
2771                 delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
2772                 if (delimit_data.cd_loop_offset == -1) {
2773                         delimit &= ~BMO_DELIM_UV;
2774                 }
2775         }
2776
2777         /* grr, shouldn't need to alloc BMO flags here */
2778         BM_mesh_elem_toolflags_ensure(bm);
2779
2780         {
2781                 BMIter iter;
2782                 BMEdge *e;
2783
2784                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
2785                         const bool is_walk_ok = (
2786                                 (select_linked_delimit_test(e, delimit, &delimit_data) == false));
2787
2788                         BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
2789                 }
2790         }
2791 }
2792
2793 static void select_linked_delimit_end(BMEditMesh *em)
2794 {
2795         BMesh *bm = em->bm;
2796
2797         BM_mesh_elem_toolflags_clear(bm);
2798 }
2799
2800 static int edbm_select_linked_exec(bContext *C, wmOperator *op)
2801 {
2802         Scene *scene = CTX_data_scene(C);
2803         ViewLayer *view_layer = CTX_data_view_layer(C);
2804
2805 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
2806         const int delimit_init = select_linked_delimit_default_from_op(op, scene->toolsettings->selectmode);
2807 #else
2808         const int delimit_init = RNA_enum_get(op->ptr, "delimit");
2809 #endif
2810
2811         uint objects_len = 0;
2812         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
2813
2814         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2815                 Object *obedit = objects[ob_index];
2816
2817                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2818                 BMesh *bm = em->bm;
2819                 BMIter iter;
2820                 BMWalker walker;
2821
2822                 int delimit = delimit_init;
2823
2824                 select_linked_delimit_validate(bm, &delimit);
2825
2826                 if (delimit) {
2827                         select_linked_delimit_begin(em->bm, delimit);
2828                 }
2829
2830                 if (em->selectmode & SCE_SELECT_VERTEX) {
2831                         BMVert *v;
2832
2833                         BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2834                                 BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
2835                         }
2836
2837                         /* exclude all delimited verts */
2838                         if (delimit) {
2839                                 BMEdge *e;
2840                                 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2841                                         if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
2842                                                 BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
2843                                                 BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
2844                                         }
2845                                 }
2846                         }
2847
2848                         BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
2849                                  BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2850                                  BMW_FLAG_TEST_HIDDEN,
2851                                  BMW_NIL_LAY);
2852
2853                         if (delimit) {
2854                                 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2855                                         if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2856                                                 BMElem *ele_walk;
2857                                                 BMW_ITER (ele_walk, &walker, v) {
2858                                                         if (ele_walk->head.htype == BM_LOOP) {
2859                                                                 BMVert *v_step = ((BMLoop *)ele_walk)->v;
2860                                                                 BM_vert_select_set(em->bm, v_step, true);
2861                                                                 BM_elem_flag_disable(v_step, BM_ELEM_TAG);
2862                                                         }
2863                                                         else {
2864                                                                 BMEdge *e_step = (BMEdge *)ele_walk;
2865                                                                 BLI_assert(ele_walk->head.htype == BM_EDGE);
2866                                                                 BM_edge_select_set(em->bm, e_step, true);
2867                                                                 BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG);
2868                                                                 BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG);
2869                                                         }
2870                                                 }
2871                                         }
2872                                 }
2873                         }
2874                         else {
2875                                 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
2876                                         if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
2877                                                 BMEdge *e_walk;
2878                                                 BMW_ITER (e_walk, &walker, v) {
2879                                                         BM_edge_select_set(em->bm, e_walk, true);
2880                                                         BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
2881                                                 }
2882                                         }
2883                                 }
2884                         }
2885
2886                         BMW_end(&walker);
2887
2888                         EDBM_selectmode_flush(em);
2889                 }
2890                 else if (em->selectmode & SCE_SELECT_EDGE) {
2891                         BMEdge *e;
2892
2893                         if (delimit) {
2894                                 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2895                                         BM_elem_flag_set(
2896                                                 e, BM_ELEM_TAG,
2897                                                 (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
2898                                 }
2899                         }
2900                         else {
2901                                 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2902                                         BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
2903                                 }
2904                         }
2905
2906                         BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
2907                                  BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2908                                  BMW_FLAG_TEST_HIDDEN,
2909                                  BMW_NIL_LAY);
2910
2911                         if (delimit) {
2912                                 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2913                                         if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
2914                                                 BMElem *ele_walk;
2915                                                 BMW_ITER (ele_walk, &walker, e) {
2916                                                         if (ele_walk->head.htype == BM_LOOP) {
2917                                                                 BMLoop *l_step = (BMLoop *)ele_walk;
2918                                                                 BM_edge_select_set(em->bm, l_step->e, true);
2919                                                                 BM_edge_select_set(em->bm, l_step->prev->e, true);
2920                                                                 BM_elem_flag_disable(l_step->e, BM_ELEM_TAG);
2921                                                         }
2922                                                         else {
2923                                                                 BMEdge *e_step = (BMEdge *)ele_walk;
2924                                                                 BLI_assert(ele_walk->head.htype == BM_EDGE);
2925                                                                 BM_edge_select_set(em->bm, e_step, true);
2926                                                                 BM_elem_flag_disable(e_step, BM_ELEM_TAG);
2927                                                         }
2928                                                 }
2929                                         }
2930                                 }
2931                         }
2932                         else {
2933                                 BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
2934                                         if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
2935                                                 BMEdge *e_walk;
2936                                                 BMW_ITER (e_walk, &walker, e) {
2937                                                         BM_edge_select_set(em->bm, e_walk, true);
2938                                                         BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
2939                                                 }
2940                                         }
2941                                 }
2942                         }
2943
2944                         BMW_end(&walker);
2945
2946                         EDBM_selectmode_flush(em);
2947                 }
2948                 else {
2949                         BMFace *f;
2950
2951                         BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2952                                 BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
2953                         }
2954
2955                         BMW_init(&walker, bm, BMW_ISLAND,
2956                                  BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
2957                                  BMW_FLAG_TEST_HIDDEN,
2958                                  BMW_NIL_LAY);
2959
2960                         BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
2961                                 if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
2962                                         BMFace *f_walk;
2963                                         BMW_ITER (f_walk, &walker, f) {
2964                                                 BM_face_select_set(bm, f_walk, true);
2965                                                 BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
2966                                         }
2967                                 }
2968                         }
2969
2970                         BMW_end(&walker);
2971                 }
2972
2973                 if (delimit) {
2974                         select_linked_delimit_end(em);
2975                 }
2976
2977                 DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
2978                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2979
2980         }
2981
2982         MEM_freeN(objects);
2983
2984         return OPERATOR_FINISHED;
2985 }
2986
2987 void MESH_OT_select_linked(wmOperatorType *ot)
2988 {
2989         PropertyRNA *prop;
2990
2991         /* identifiers */
2992         ot->name = "Select Linked All";
2993         ot->idname = "MESH_OT_select_linked";
2994         ot->description = "Select all vertices connected to the current selection";
2995
2996         /* api callbacks */
2997         ot->exec = edbm_select_linked_exec;
2998         ot->poll = ED_operator_editmesh;
2999
3000         /* flags */
3001         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3002
3003         prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
3004                                  "Delimit selected region");
3005 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
3006         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3007 #else
3008         UNUSED_VARS(prop);
3009 #endif
3010 }
3011
3012 /** \} */
3013
3014 /* -------------------------------------------------------------------- */
3015 /** \name Select Linked (Cursor Pick) Operator
3016  * \{ */
3017
3018 static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
3019
3020 static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
3021 {
3022         BMesh *bm = em->bm;
3023         BMWalker walker;
3024
3025         select_linked_delimit_validate(bm, &delimit);
3026
3027         if (delimit) {
3028                 select_linked_delimit_begin(bm, delimit);
3029         }
3030
3031         /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
3032
3033         if (ele->head.htype == BM_VERT) {
3034                 BMVert *eve = (BMVert *)ele;
3035
3036                 BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
3037                          BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
3038                          BMW_FLAG_TEST_HIDDEN,
3039                          BMW_NIL_LAY);
3040
3041                 if (delimit) {
3042                         BMElem *ele_walk;
3043                         BMW_ITER (ele_walk, &walker, eve) {
3044                                 if (ele_walk->head.htype == BM_LOOP) {
3045                                         BMVert *v_step = ((BMLoop *)ele_walk)->v;
3046                                         BM_vert_select_set(bm, v_step, sel);
3047                                 }
3048                                 else {
3049                                         BMEdge *e_step = (BMEdge *)ele_walk;
3050                                         BLI_assert(ele_walk->head.htype == BM_EDGE);
3051                                         BM_edge_select_set(bm, e_step, sel);
3052                                 }
3053                         }
3054                 }
3055                 else {
3056                         BMEdge *e_walk;
3057                         BMW_ITER (e_walk, &walker, eve) {