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