Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_view3d / view3d_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) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_view3d/view3d_select.c
28  *  \ingroup spview3d
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34 #include <math.h>
35 #include <float.h>
36 #include <assert.h>
37
38 #include "DNA_action_types.h"
39 #include "DNA_armature_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_meta_types.h"
42 #include "DNA_mesh_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_tracking_types.h"
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_array.h"
51 #include "BLI_math.h"
52 #include "BLI_lasso_2d.h"
53 #include "BLI_rect.h"
54 #include "BLI_linklist.h"
55 #include "BLI_listbase.h"
56 #include "BLI_string.h"
57 #include "BLI_utildefines.h"
58
59 #ifdef __BIG_ENDIAN__
60 #  include "BLI_endian_switch.h"
61 #endif
62
63 /* vertex box select */
64 #include "IMB_imbuf_types.h"
65 #include "IMB_imbuf.h"
66 #include "BKE_global.h"
67
68 #include "BKE_armature.h"
69 #include "BKE_context.h"
70 #include "BKE_curve.h"
71 #include "BKE_layer.h"
72 #include "BKE_mball.h"
73 #include "BKE_mesh.h"
74 #include "BKE_object.h"
75 #include "BKE_paint.h"
76 #include "BKE_editmesh.h"
77 #include "BKE_scene.h"
78 #include "BKE_tracking.h"
79
80 #include "DEG_depsgraph.h"
81
82 #include "WM_api.h"
83 #include "WM_types.h"
84
85 #include "RNA_access.h"
86 #include "RNA_define.h"
87 #include "RNA_enum_types.h"
88
89 #include "ED_armature.h"
90 #include "ED_curve.h"
91 #include "ED_lattice.h"
92 #include "ED_particle.h"
93 #include "ED_mesh.h"
94 #include "ED_object.h"
95 #include "ED_screen.h"
96 #include "ED_sculpt.h"
97 #include "ED_mball.h"
98
99 #include "UI_interface.h"
100
101 #include "GPU_draw.h"
102 #include "GPU_glew.h"
103 #include "GPU_matrix.h"
104
105 #include "view3d_intern.h"  /* own include */
106
107 // #include "PIL_time_utildefines.h"
108
109 float ED_view3d_select_dist_px(void)
110 {
111         return 75.0f * U.pixelsize;
112 }
113
114 /* TODO: should return whether there is valid context to continue */
115 void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
116 {
117         memset(vc, 0, sizeof(ViewContext));
118         vc->ar = CTX_wm_region(C);
119         vc->depsgraph = CTX_data_depsgraph(C);
120         vc->scene = CTX_data_scene(C);
121         vc->view_layer = CTX_data_view_layer(C);
122         vc->v3d = CTX_wm_view3d(C);
123         vc->win = CTX_wm_window(C);
124         vc->rv3d = CTX_wm_region_view3d(C);
125         vc->obact = CTX_data_active_object(C);
126         vc->obedit = CTX_data_edit_object(C);
127 }
128
129 void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
130 {
131         vc->obact = obact;
132         if (vc->obedit) {
133                 BLI_assert(BKE_object_is_in_editmode(obact));
134                 vc->obedit = obact;
135                 /* previous selections are now invalid. */
136                 vc->v3d->flag |= V3D_INVALID_BACKBUF;
137
138                 if (vc->em) {
139                         vc->em = BKE_editmesh_from_object(vc->obedit);
140                 }
141         }
142 }
143
144 /* ********************** view3d_select: selection manipulations ********************* */
145
146 /* local prototypes */
147
148 static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool select)
149 {
150         BMVert *eve;
151         BMIter iter;
152         unsigned int index = bm_wireoffs;
153
154         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
155                 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
156                         if (EDBM_backbuf_check(index)) {
157                                 BM_vert_select_set(em->bm, eve, select);
158                         }
159                 }
160                 index++;
161         }
162 }
163
164 static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const bool select)
165 {
166         BMEdge *eed;
167         BMIter iter;
168         unsigned int index = bm_solidoffs;
169
170         BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
171                 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
172                         if (EDBM_backbuf_check(index)) {
173                                 BM_edge_select_set(em->bm, eed, select);
174                         }
175                 }
176                 index++;
177         }
178 }
179
180 static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const bool select)
181 {
182         BMFace *efa;
183         BMIter iter;
184         unsigned int index = 1;
185
186         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
187                 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
188                         if (EDBM_backbuf_check(index)) {
189                                 BM_face_select_set(em->bm, efa, select);
190                         }
191                 }
192                 index++;
193         }
194 }
195
196
197 /* object mode, edbm_ prefix is confusing here, rename? */
198 static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const bool select)
199 {
200         MVert *mv = me->mvert;
201         unsigned int index;
202
203         if (mv) {
204                 for (index = 1; index <= me->totvert; index++, mv++) {
205                         if (EDBM_backbuf_check(index)) {
206                                 if (!(mv->flag & ME_HIDE)) {
207                                         mv->flag = select ? (mv->flag | SELECT) : (mv->flag & ~SELECT);
208                                 }
209                         }
210                 }
211         }
212 }
213
214 /* object mode, edbm_ prefix is confusing here, rename? */
215 static void edbm_backbuf_check_and_select_tfaces(Mesh *me, const bool select)
216 {
217         MPoly *mpoly = me->mpoly;
218         unsigned int index;
219
220         if (mpoly) {
221                 for (index = 1; index <= me->totpoly; index++, mpoly++) {
222                         if (EDBM_backbuf_check(index)) {
223                                 mpoly->flag = select ? (mpoly->flag | ME_FACE_SEL) : (mpoly->flag & ~ME_FACE_SEL);
224                         }
225                 }
226         }
227 }
228
229 /* *********************** GESTURE AND LASSO ******************* */
230
231 typedef struct LassoSelectUserData {
232         ViewContext *vc;
233         const rcti *rect;
234         const rctf *rect_fl;
235         rctf       _rect_fl;
236         const int (*mcords)[2];
237         int moves;
238         bool select;
239
240         /* runtime */
241         int pass;
242         bool is_done;
243         bool is_changed;
244 } LassoSelectUserData;
245
246 static void view3d_userdata_lassoselect_init(
247         LassoSelectUserData *r_data,
248         ViewContext *vc, const rcti *rect, const int (*mcords)[2],
249         const int moves, const bool select)
250 {
251         r_data->vc = vc;
252
253         r_data->rect = rect;
254         r_data->rect_fl = &r_data->_rect_fl;
255         BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
256
257         r_data->mcords = mcords;
258         r_data->moves = moves;
259         r_data->select = select;
260
261         /* runtime */
262         r_data->pass = 0;
263         r_data->is_done = false;
264         r_data->is_changed = false;
265 }
266
267 static int view3d_selectable_data(bContext *C)
268 {
269         Object *ob = CTX_data_active_object(C);
270
271         if (!ED_operator_region_view3d_active(C))
272                 return 0;
273
274         if (ob) {
275                 if (ob->mode & OB_MODE_EDIT) {
276                         if (ob->type == OB_FONT) {
277                                 return 0;
278                         }
279                 }
280                 else {
281                         if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) &&
282                             !BKE_paint_select_elem_test(ob))
283                         {
284                                 return 0;
285                         }
286                 }
287         }
288
289         return 1;
290 }
291
292
293 /* helper also for borderselect */
294 static bool edge_fully_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
295 {
296         return BLI_rctf_isect_pt_v(rect, v1) && BLI_rctf_isect_pt_v(rect, v2);
297 }
298
299 static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
300 {
301         int d1, d2, d3, d4;
302
303         /* check points in rect */
304         if (edge_fully_inside_rect(rect, v1, v2)) return 1;
305
306         /* check points completely out rect */
307         if (v1[0] < rect->xmin && v2[0] < rect->xmin) return 0;
308         if (v1[0] > rect->xmax && v2[0] > rect->xmax) return 0;
309         if (v1[1] < rect->ymin && v2[1] < rect->ymin) return 0;
310         if (v1[1] > rect->ymax && v2[1] > rect->ymax) return 0;
311
312         /* simple check lines intersecting. */
313         d1 = (v1[1] - v2[1]) * (v1[0] - rect->xmin) + (v2[0] - v1[0]) * (v1[1] - rect->ymin);
314         d2 = (v1[1] - v2[1]) * (v1[0] - rect->xmin) + (v2[0] - v1[0]) * (v1[1] - rect->ymax);
315         d3 = (v1[1] - v2[1]) * (v1[0] - rect->xmax) + (v2[0] - v1[0]) * (v1[1] - rect->ymax);
316         d4 = (v1[1] - v2[1]) * (v1[0] - rect->xmax) + (v2[0] - v1[0]) * (v1[1] - rect->ymin);
317
318         if (d1 < 0 && d2 < 0 && d3 < 0 && d4 < 0) return 0;
319         if (d1 > 0 && d2 > 0 && d3 > 0 && d4 > 0) return 0;
320
321         return 1;
322 }
323
324 static void do_lasso_select_pose__doSelectBone(
325         void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
326 {
327         LassoSelectUserData *data = userData;
328         bArmature *arm = data->vc->obact->data;
329
330         if (PBONE_SELECTABLE(arm, pchan->bone)) {
331                 bool is_point_done = false;
332                 int points_proj_tot = 0;
333
334                 const int x0 = screen_co_a[0];
335                 const int y0 = screen_co_a[1];
336                 const int x1 = screen_co_b[0];
337                 const int y1 = screen_co_b[1];
338
339                 /* project head location to screenspace */
340                 if (x0 != IS_CLIPPED) {
341                         points_proj_tot++;
342                         if (BLI_rcti_isect_pt(data->rect, x0, y0) &&
343                             BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX))
344                         {
345                                 is_point_done = true;
346                         }
347                 }
348
349                 /* project tail location to screenspace */
350                 if (x1 != IS_CLIPPED) {
351                         points_proj_tot++;
352                         if (BLI_rcti_isect_pt(data->rect, x1, y1) &&
353                             BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX))
354                         {
355                                 is_point_done = true;
356                         }
357                 }
358
359                 /* if one of points selected, we skip the bone itself */
360                 if ((is_point_done == true) ||
361                     ((is_point_done == false) && (points_proj_tot == 2) &&
362                      BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX)))
363                 {
364                         if (data->select) pchan->bone->flag |=  BONE_SELECTED;
365                         else              pchan->bone->flag &= ~BONE_SELECTED;
366                         data->is_changed = true;
367                 }
368                 data->is_changed |= is_point_done;
369         }
370 }
371 static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, const bool select)
372 {
373         ViewContext vc_tmp;
374         LassoSelectUserData data;
375         rcti rect;
376
377         if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) {
378                 return;
379         }
380
381         vc_tmp = *vc;
382         vc_tmp.obact = ob;
383
384         BLI_lasso_boundbox(&rect, mcords, moves);
385
386         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
387
388         ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
389
390         pose_foreachScreenBone(&vc_tmp, do_lasso_select_pose__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
391
392         if (data.is_changed) {
393                 bArmature *arm = ob->data;
394                 if (arm->flag & ARM_HAS_VIZ_DEPS) {
395                         /* mask modifier ('armature' mode), etc. */
396                         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
397                 }
398                 /* bone selection status is on armature not object */
399                 DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
400         }
401 }
402
403 static void object_deselect_all_visible(ViewLayer *view_layer)
404 {
405         Base *base;
406
407         for (base = view_layer->object_bases.first; base; base = base->next) {
408                 if (BASE_SELECTABLE(base)) {
409                         ED_object_base_select(base, BA_DESELECT);
410                 }
411         }
412 }
413
414 static void do_lasso_select_objects(
415         ViewContext *vc, const int mcords[][2], const short moves,
416         const bool extend, const bool select)
417 {
418         bool is_pose_mode = vc->obact ? (vc->obact->mode & OB_MODE_POSE) : false;
419         Base *base;
420
421         if (extend == false && select)
422                 object_deselect_all_visible(vc->view_layer);
423
424         for (base = vc->view_layer->object_bases.first; base; base = base->next) {
425                 if (BASE_SELECTABLE(base)) { /* use this to avoid un-needed lasso lookups */
426                         if (
427 #ifdef USE_OBJECT_MODE_STRICT
428                             (is_pose_mode == false) &&
429 #endif
430                             ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK)
431                         {
432                                 if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) {
433
434                                         ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
435                                 }
436                         }
437                         if (is_pose_mode && (base->object->mode & OB_MODE_POSE)) {
438                                 do_lasso_select_pose(vc, base->object, mcords, moves, select);
439                         }
440                 }
441         }
442 }
443
444 static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
445 {
446         LassoSelectUserData *data = userData;
447
448         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
449             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
450         {
451                 BM_vert_select_set(data->vc->em->bm, eve, data->select);
452         }
453 }
454 static void do_lasso_select_mesh__doSelectEdge(
455         void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
456 {
457         LassoSelectUserData *data = userData;
458
459         if (EDBM_backbuf_check(bm_solidoffs + index)) {
460                 const int x0 = screen_co_a[0];
461                 const int y0 = screen_co_a[1];
462                 const int x1 = screen_co_b[0];
463                 const int y1 = screen_co_b[1];
464
465                 if (data->pass == 0) {
466                         if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)  &&
467                             BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, IS_CLIPPED) &&
468                             BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, IS_CLIPPED))
469                         {
470                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
471                                 data->is_done = true;
472                         }
473                 }
474                 else {
475                         if (BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, IS_CLIPPED)) {
476                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
477                         }
478                 }
479         }
480 }
481 static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
482 {
483         LassoSelectUserData *data = userData;
484
485         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
486             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
487         {
488                 BM_face_select_set(data->vc->em->bm, efa, data->select);
489         }
490 }
491
492 static void do_lasso_select_mesh(
493         ViewContext *vc,
494         const int mcords[][2], short moves, bool extend, bool select)
495 {
496         LassoSelectUserData data;
497         ToolSettings *ts = vc->scene->toolsettings;
498         rcti rect;
499         int bbsel;
500
501         /* set editmesh */
502         vc->em = BKE_editmesh_from_object(vc->obedit);
503
504         BLI_lasso_boundbox(&rect, mcords, moves);
505
506         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
507
508         if (extend == false && select)
509                 EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
510
511         /* for non zbuf projections, don't change the GL state */
512         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
513
514         gpuLoadMatrix(vc->rv3d->viewmat);
515         bbsel = EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
516
517         if (ts->selectmode & SCE_SELECT_VERTEX) {
518                 if (bbsel) {
519                         edbm_backbuf_check_and_select_verts(vc->em, select);
520                 }
521                 else {
522                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
523                 }
524         }
525         if (ts->selectmode & SCE_SELECT_EDGE) {
526                 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
527                 data.pass = 0;
528                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
529
530                 if (data.is_done == false) {
531                         data.pass = 1;
532                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
533                 }
534         }
535
536         if (ts->selectmode & SCE_SELECT_FACE) {
537                 if (bbsel) {
538                         edbm_backbuf_check_and_select_faces(vc->em, select);
539                 }
540                 else {
541                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
542                 }
543         }
544
545         EDBM_backbuf_free();
546         EDBM_selectmode_flush(vc->em);
547 }
548
549 static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
550 {
551         LassoSelectUserData *data = userData;
552         Object *obedit = data->vc->obedit;
553         Curve *cu = (Curve *)obedit->data;
554
555         if (BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) {
556                 if (bp) {
557                         bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
558                 }
559                 else {
560                         if (cu->drawflag & CU_HIDE_HANDLES) {
561                                 /* can only be (beztindex == 0) here since handles are hidden */
562                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
563                         }
564                         else {
565                                 if (beztindex == 0) {
566                                         bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
567                                 }
568                                 else if (beztindex == 1) {
569                                         bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
570                                 }
571                                 else {
572                                         bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
573                                 }
574                         }
575                 }
576         }
577 }
578
579 static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
580 {
581         LassoSelectUserData data;
582         rcti rect;
583
584         BLI_lasso_boundbox(&rect, mcords, moves);
585
586         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
587
588         if (extend == false && select) {
589                 Curve *curve = (Curve *) vc->obedit->data;
590                 ED_curve_deselect_all(curve->editnurb);
591         }
592
593         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
594         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
595         BKE_curve_nurb_vert_active_validate(vc->obedit->data);
596 }
597
598 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
599 {
600         LassoSelectUserData *data = userData;
601
602         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
603             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
604         {
605                 bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
606         }
607 }
608 static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
609 {
610         LassoSelectUserData data;
611         rcti rect;
612
613         BLI_lasso_boundbox(&rect, mcords, moves);
614
615         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
616
617         if (extend == false && select)
618                 ED_lattice_flags_set(vc->obedit, 0);
619
620         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
621         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
622 }
623
624 static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
625 {
626         LassoSelectUserData *data = userData;
627         bArmature *arm = data->vc->obedit->data;
628
629         if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) {
630                 bool is_point_done = false;
631                 int points_proj_tot = 0;
632
633                 const int x0 = screen_co_a[0];
634                 const int y0 = screen_co_a[1];
635                 const int x1 = screen_co_b[0];
636                 const int y1 = screen_co_b[1];
637
638                 /* project head location to screenspace */
639                 if (x0 != IS_CLIPPED) {
640                         points_proj_tot++;
641                         if (BLI_rcti_isect_pt(data->rect, x0, y0) &&
642                             BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX))
643                         {
644                                 is_point_done = true;
645                                 if (data->select) ebone->flag |=  BONE_ROOTSEL;
646                                 else              ebone->flag &= ~BONE_ROOTSEL;
647                         }
648                 }
649
650                 /* project tail location to screenspace */
651                 if (x1 != IS_CLIPPED) {
652                         points_proj_tot++;
653                         if (BLI_rcti_isect_pt(data->rect, x1, y1) &&
654                             BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX))
655                         {
656                                 is_point_done = true;
657                                 if (data->select) ebone->flag |=  BONE_TIPSEL;
658                                 else              ebone->flag &= ~BONE_TIPSEL;
659                         }
660                 }
661
662                 /* if one of points selected, we skip the bone itself */
663                 if ((is_point_done == false) && (points_proj_tot == 2) &&
664                     BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX))
665                 {
666                         if (data->select) ebone->flag |=  (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
667                         else              ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
668                         data->is_changed = true;
669                 }
670
671                 data->is_changed |= is_point_done;
672         }
673 }
674
675 static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
676 {
677         LassoSelectUserData data;
678         rcti rect;
679
680         BLI_lasso_boundbox(&rect, mcords, moves);
681
682         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
683
684         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
685
686         if (extend == false && select)
687                 ED_armature_edit_deselect_all_visible(vc->obedit);
688
689         armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
690
691         if (data.is_changed) {
692                 bArmature *arm = vc->obedit->data;
693                 ED_armature_edit_sync_selection(arm->edbo);
694                 ED_armature_edit_validate_active(arm);
695                 WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit);
696         }
697 }
698
699 static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2])
700 {
701         LassoSelectUserData *data = userData;
702
703         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
704             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX))
705         {
706                 if (data->select) ml->flag |=  SELECT;
707                 else              ml->flag &= ~SELECT;
708                 data->is_changed = true;
709         }
710 }
711 static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
712 {
713         LassoSelectUserData data;
714         rcti rect;
715
716         MetaBall *mb = (MetaBall *)vc->obedit->data;
717
718         if (extend == false && select)
719                 BKE_mball_deselect_all(mb);
720
721         BLI_lasso_boundbox(&rect, mcords, moves);
722
723         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
724
725         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
726
727         mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
728 }
729
730 static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
731 {
732         LassoSelectUserData *data = userData;
733
734         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
735             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
736         {
737                 SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
738         }
739 }
740 static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
741 {
742         const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
743         Object *ob = vc->obact;
744         Mesh *me = ob->data;
745         rcti rect;
746
747         if (me == NULL || me->totvert == 0)
748                 return;
749
750         if (extend == false && select)
751                 paintvert_deselect_all_visible(ob, SEL_DESELECT, false);  /* flush selection at the end */
752
753         BLI_lasso_boundbox(&rect, mcords, moves);
754
755         if (use_zbuf) {
756                 bm_vertoffs = me->totvert + 1; /* max index array */
757
758                 EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
759
760                 edbm_backbuf_check_and_select_verts_obmode(me, select);
761
762                 EDBM_backbuf_free();
763         }
764         else {
765                 LassoSelectUserData data;
766
767                 view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
768
769                 ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
770
771                 meshobject_foreachScreenVert(vc, do_lasso_select_meshobject__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
772
773         }
774
775         if (select == false) {
776                 BKE_mesh_mselect_validate(me);
777         }
778         paintvert_flush_flags(ob);
779 }
780 static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
781 {
782         Object *ob = vc->obact;
783         Mesh *me = ob->data;
784         rcti rect;
785
786         if (me == NULL || me->totpoly == 0)
787                 return;
788
789         if (extend == false && select)
790                 paintface_deselect_all_visible(ob, SEL_DESELECT, false);  /* flush selection at the end */
791
792         bm_vertoffs = me->totpoly + 1; /* max index array */
793
794         BLI_lasso_boundbox(&rect, mcords, moves);
795         EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
796
797         edbm_backbuf_check_and_select_tfaces(me, select);
798
799         EDBM_backbuf_free();
800
801         paintface_flush_flags(ob, SELECT);
802 }
803
804 #if 0
805 static void do_lasso_select_node(int mcords[][2], short moves, const bool select)
806 {
807         SpaceNode *snode = sa->spacedata.first;
808
809         bNode *node;
810         rcti rect;
811         int node_cent[2];
812         float node_centf[2];
813
814         BLI_lasso_boundbox(&rect, mcords, moves);
815
816         /* store selection in temp test flag */
817         for (node = snode->edittree->nodes.first; node; node = node->next) {
818                 node_centf[0] = BLI_RCT_CENTER_X(&node->totr);
819                 node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
820
821                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
822                 if (BLI_rcti_isect_pt_v(&rect, node_cent) && BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])) {
823                         if (select) {
824                                 node->flag |= SELECT;
825                         }
826                         else {
827                                 node->flag &= ~SELECT;
828                         }
829                 }
830         }
831         BIF_undo_push("Lasso select nodes");
832 }
833 #endif
834
835 static void view3d_lasso_select(
836         bContext *C, ViewContext *vc,
837         const int mcords[][2], short moves,
838         bool extend, bool select)
839 {
840         Object *ob = CTX_data_active_object(C);
841
842         if (vc->obedit == NULL) { /* Object Mode */
843                 if (BKE_paint_select_face_test(ob)) {
844                         do_lasso_select_paintface(vc, mcords, moves, extend, select);
845                 }
846                 else if (BKE_paint_select_vert_test(ob)) {
847                         do_lasso_select_paintvert(vc, mcords, moves, extend, select);
848                 }
849                 else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
850                         /* pass */
851                 }
852                 else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
853                         PE_lasso_select(C, mcords, moves, extend, select);
854                 }
855                 else {
856                         do_lasso_select_objects(vc, mcords, moves, extend, select);
857                         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
858                 }
859         }
860         else { /* Edit Mode */
861
862                 FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, ob->mode, ob_iter) {
863                         ED_view3d_viewcontext_init_object(vc, ob_iter);
864
865                         switch (vc->obedit->type) {
866                                 case OB_MESH:
867                                         do_lasso_select_mesh(vc, mcords, moves, extend, select);
868                                         break;
869                                 case OB_CURVE:
870                                 case OB_SURF:
871                                         do_lasso_select_curve(vc, mcords, moves, extend, select);
872                                         break;
873                                 case OB_LATTICE:
874                                         do_lasso_select_lattice(vc, mcords, moves, extend, select);
875                                         break;
876                                 case OB_ARMATURE:
877                                         do_lasso_select_armature(vc, mcords, moves, extend, select);
878                                         break;
879                                 case OB_MBALL:
880                                         do_lasso_select_meta(vc, mcords, moves, extend, select);
881                                         break;
882                                 default:
883                                         assert(!"lasso select on incorrect object type");
884                                         break;
885                         }
886
887                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data);
888                 }
889                 FOREACH_OBJECT_IN_MODE_END;
890         }
891 }
892
893
894 /* lasso operator gives properties, but since old code works
895  * with short array we convert */
896 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
897 {
898         ViewContext vc;
899         int mcords_tot;
900         const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
901
902         if (mcords) {
903                 bool extend, select;
904                 view3d_operator_needs_opengl(C);
905
906                 /* setup view context for argument to callbacks */
907                 ED_view3d_viewcontext_init(C, &vc);
908
909                 extend = RNA_boolean_get(op->ptr, "extend");
910                 select = !RNA_boolean_get(op->ptr, "deselect");
911                 view3d_lasso_select(C, &vc, mcords, mcords_tot, extend, select);
912
913                 MEM_freeN((void *)mcords);
914
915                 return OPERATOR_FINISHED;
916         }
917         return OPERATOR_PASS_THROUGH;
918 }
919
920 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
921 {
922         ot->name = "Lasso Select";
923         ot->description = "Select items using lasso selection";
924         ot->idname = "VIEW3D_OT_select_lasso";
925
926         ot->invoke = WM_gesture_lasso_invoke;
927         ot->modal = WM_gesture_lasso_modal;
928         ot->exec = view3d_lasso_select_exec;
929         ot->poll = view3d_selectable_data;
930         ot->cancel = WM_gesture_lasso_cancel;
931
932         /* flags */
933         ot->flag = OPTYPE_UNDO;
934
935         /* properties */
936         WM_operator_properties_gesture_lasso_select(ot);
937 }
938
939 /* ************************** mouse select ************************* */
940
941 /* The max number of menu items in an object select menu */
942 typedef struct SelMenuItemF {
943         char idname[MAX_ID_NAME - 2];
944         int icon;
945 } SelMenuItemF;
946
947 #define SEL_MENU_SIZE   22
948 static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE];
949
950 /* special (crappy) operator only for menu select */
951 static const EnumPropertyItem *object_select_menu_enum_itemf(
952         bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
953 {
954         EnumPropertyItem *item = NULL, item_tmp = {0};
955         int totitem = 0;
956         int i = 0;
957
958         /* don't need context but avoid docgen using this */
959         if (C == NULL || object_mouse_select_menu_data[i].idname[0] == '\0') {
960                 return DummyRNA_NULL_items;
961         }
962
963         for (; i < SEL_MENU_SIZE && object_mouse_select_menu_data[i].idname[0] != '\0'; i++) {
964                 item_tmp.name = object_mouse_select_menu_data[i].idname;
965                 item_tmp.identifier = object_mouse_select_menu_data[i].idname;
966                 item_tmp.value = i;
967                 item_tmp.icon = object_mouse_select_menu_data[i].icon;
968                 RNA_enum_item_add(&item, &totitem, &item_tmp);
969         }
970
971         RNA_enum_item_end(&item, &totitem);
972         *r_free = true;
973
974         return item;
975 }
976
977 static int object_select_menu_exec(bContext *C, wmOperator *op)
978 {
979         const int name_index = RNA_enum_get(op->ptr, "name");
980         const bool toggle = RNA_boolean_get(op->ptr, "toggle");
981         bool changed = false;
982         const char *name = object_mouse_select_menu_data[name_index].idname;
983
984         if (!toggle) {
985                 CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
986                 {
987                         if ((base->flag & BASE_SELECTED) != 0) {
988                                 ED_object_base_select(base, BA_DESELECT);
989                                 changed = true;
990                         }
991                 }
992                 CTX_DATA_END;
993         }
994
995         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
996         {
997                 /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
998                 if (STREQ(name, base->object->id.name + 2)) {
999                         ED_object_base_activate(C, base);
1000                         ED_object_base_select(base, BA_SELECT);
1001                         changed = true;
1002                 }
1003         }
1004         CTX_DATA_END;
1005
1006         /* weak but ensures we activate menu again before using the enum */
1007         memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
1008
1009         /* undo? */
1010         if (changed) {
1011                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
1012                 return OPERATOR_FINISHED;
1013         }
1014         else {
1015                 return OPERATOR_CANCELLED;
1016         }
1017 }
1018
1019 void VIEW3D_OT_select_menu(wmOperatorType *ot)
1020 {
1021         PropertyRNA *prop;
1022
1023         /* identifiers */
1024         ot->name = "Select Menu";
1025         ot->description = "Menu object selection";
1026         ot->idname = "VIEW3D_OT_select_menu";
1027
1028         /* api callbacks */
1029         ot->invoke = WM_menu_invoke;
1030         ot->exec = object_select_menu_exec;
1031
1032         /* flags */
1033         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1034
1035         /* keyingset to use (dynamic enum) */
1036         prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", "");
1037         RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
1038         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE);
1039         ot->prop = prop;
1040
1041         RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle selection instead of deselecting everything first");
1042 }
1043
1044 static void deselectall_except(ViewLayer *view_layer, Base *b)   /* deselect all except b */
1045 {
1046         for (Base *base = view_layer->object_bases.first; base; base = base->next) {
1047                 if (base->flag & BASE_SELECTED) {
1048                         if (b != base) {
1049                                 ED_object_base_select(base, BA_DESELECT);
1050                         }
1051                 }
1052         }
1053 }
1054
1055 static Base *object_mouse_select_menu(
1056         bContext *C, ViewContext *vc, unsigned int *buffer, int hits,
1057         const int mval[2], bool toggle)
1058 {
1059         short baseCount = 0;
1060         bool ok;
1061         LinkNode *linklist = NULL;
1062
1063         /* handle base->object->select_color */
1064         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
1065         {
1066                 ok = false;
1067
1068                 /* two selection methods, the CTRL select uses max dist of 15 */
1069                 if (buffer) {
1070                         for (int a = 0; a < hits; a++) {
1071                                 /* index was converted */
1072                                 if (base->object->select_color == (buffer[(4 * a) + 3] & ~0xFFFF0000)) {
1073                                         ok = true;
1074                                         break;
1075                                 }
1076                         }
1077                 }
1078                 else {
1079                         const int dist = 15 * U.pixelsize;
1080                         if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) {
1081                                 const int delta_px[2] = {base->sx - mval[0], base->sy - mval[1]};
1082                                 if (len_manhattan_v2_int(delta_px) < dist) {
1083                                         ok = true;
1084                                 }
1085                         }
1086                 }
1087
1088                 if (ok) {
1089                         baseCount++;
1090                         BLI_linklist_prepend(&linklist, base);
1091
1092                         if (baseCount == SEL_MENU_SIZE)
1093                                 break;
1094                 }
1095         }
1096         CTX_DATA_END;
1097
1098         if (baseCount == 0) {
1099                 return NULL;
1100         }
1101         if (baseCount == 1) {
1102                 Base *base = (Base *)linklist->link;
1103                 BLI_linklist_free(linklist, NULL);
1104                 return base;
1105         }
1106         else {
1107                 /* UI, full in static array values that we later use in an enum function */
1108                 LinkNode *node;
1109                 int i;
1110
1111                 memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
1112
1113                 for (node = linklist, i = 0; node; node = node->next, i++) {
1114                         Base *base = node->link;
1115                         Object *ob = base->object;
1116                         const char *name = ob->id.name + 2;
1117
1118                         BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME - 2);
1119                         object_mouse_select_menu_data[i].icon = UI_icon_from_id(&ob->id);
1120                 }
1121
1122                 {
1123                         wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false);
1124                         PointerRNA ptr;
1125
1126                         WM_operator_properties_create_ptr(&ptr, ot);
1127                         RNA_boolean_set(&ptr, "toggle", toggle);
1128                         WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
1129                         WM_operator_properties_free(&ptr);
1130                 }
1131
1132                 BLI_linklist_free(linklist, NULL);
1133                 return NULL;
1134         }
1135 }
1136
1137 static bool selectbuffer_has_bones(const uint *buffer, const uint hits)
1138 {
1139         unsigned int i;
1140         for (i = 0; i < hits; i++) {
1141                 if (buffer[(4 * i) + 3] & 0xFFFF0000) {
1142                         return true;
1143                 }
1144         }
1145         return false;
1146 }
1147
1148 /* utility function for mixed_bones_object_selectbuffer */
1149 static int selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const int hits15)
1150 {
1151         return hits15;
1152 }
1153
1154 static int selectbuffer_ret_hits_9(unsigned int *buffer, const int hits15, const int hits9)
1155 {
1156         const int offs = 4 * hits15;
1157         memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(unsigned int));
1158         return hits9;
1159 }
1160
1161 static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits15, const int hits9, const int hits5)
1162 {
1163         const int offs = 4 * hits15 + 4 * hits9;
1164         memcpy(buffer, buffer + offs, 4 * hits5  * sizeof(unsigned int));
1165         return hits5;
1166 }
1167
1168 /* we want a select buffer with bones, if there are... */
1169 /* so check three selection levels and compare */
1170 static int mixed_bones_object_selectbuffer(
1171         ViewContext *vc, unsigned int *buffer, const int mval[2],
1172         bool use_cycle, bool enumerate,
1173         bool *r_do_nearest)
1174 {
1175         rcti rect;
1176         int hits15, hits9 = 0, hits5 = 0;
1177         bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
1178         static int last_mval[2] = {-100, -100};
1179         bool do_nearest = false;
1180         View3D *v3d = vc->v3d;
1181
1182         /* define if we use solid nearest select or not */
1183         if (use_cycle) {
1184                 if (v3d->drawtype > OB_WIRE) {
1185                         do_nearest = true;
1186                         if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
1187                                 do_nearest = false;
1188                         }
1189                 }
1190                 copy_v2_v2_int(last_mval, mval);
1191         }
1192         else {
1193                 if (v3d->drawtype > OB_WIRE) {
1194                         do_nearest = true;
1195                 }
1196         }
1197
1198         if (r_do_nearest) {
1199                 *r_do_nearest = do_nearest;
1200         }
1201
1202         do_nearest = do_nearest && !enumerate;
1203
1204         const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
1205         int hits = 0;
1206
1207         /* we _must_ end cache before return, use 'goto finally' */
1208         view3d_opengl_select_cache_begin();
1209
1210         BLI_rcti_init_pt_radius(&rect, mval, 14);
1211         hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
1212         if (hits15 == 1) {
1213                 hits = selectbuffer_ret_hits_15(buffer, hits15);
1214                 goto finally;
1215         }
1216         else if (hits15 > 0) {
1217                 int offs;
1218                 has_bones15 = selectbuffer_has_bones(buffer, hits15);
1219
1220                 offs = 4 * hits15;
1221                 BLI_rcti_init_pt_radius(&rect, mval, 9);
1222                 hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
1223                 if (hits9 == 1) {
1224                         hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
1225                         goto finally;
1226                 }
1227                 else if (hits9 > 0) {
1228                         has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
1229
1230                         offs += 4 * hits9;
1231                         BLI_rcti_init_pt_radius(&rect, mval, 5);
1232                         hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
1233                         if (hits5 == 1) {
1234                                 hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1235                                 goto finally;
1236                         }
1237                         else if (hits5 > 0) {
1238                                 has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
1239                         }
1240                 }
1241
1242                 if      (has_bones5)  { hits = selectbuffer_ret_hits_5(buffer,  hits15, hits9, hits5); goto finally; }
1243                 else if (has_bones9)  { hits = selectbuffer_ret_hits_9(buffer,  hits15, hits9); goto finally; }
1244                 else if (has_bones15) { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
1245
1246                 if      (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer,  hits15, hits9, hits5); goto finally; }
1247                 else if (hits9 > 0) { hits = selectbuffer_ret_hits_9(buffer,  hits15, hits9); goto finally; }
1248                 else                { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
1249         }
1250
1251 finally:
1252         view3d_opengl_select_cache_end();
1253
1254 #ifdef USE_OBJECT_MODE_STRICT
1255         {
1256                 const bool is_pose_mode = (vc->obact && vc->obact->mode & OB_MODE_POSE);
1257                 struct {
1258                         uint data[4];
1259                 } *buffer4 = (void *)buffer;
1260                 uint j = 0;
1261                 for (uint i = 0; i < hits; i++) {
1262                         if (((buffer4[i].data[3] & 0xFFFF0000) != 0) == is_pose_mode) {
1263                                 if (i != j) {
1264                                         buffer4[i] = buffer4[j];
1265                                 }
1266                                 j++;
1267                         }
1268                 }
1269                 hits = j;
1270         }
1271 #endif
1272
1273         return hits;
1274 }
1275
1276 /* returns basact */
1277 static Base *mouse_select_eval_buffer(
1278         ViewContext *vc, const uint *buffer, int hits,
1279         Base *startbase, bool has_bones, bool do_nearest)
1280 {
1281         ViewLayer *view_layer = vc->view_layer;
1282         Base *base, *basact = NULL;
1283         int a;
1284
1285         if (do_nearest) {
1286                 unsigned int min = 0xFFFFFFFF;
1287                 int selcol = 0, notcol = 0;
1288
1289
1290                 if (has_bones) {
1291                         /* we skip non-bone hits */
1292                         for (a = 0; a < hits; a++) {
1293                                 if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000) ) {
1294                                         min = buffer[4 * a + 1];
1295                                         selcol = buffer[4 * a + 3] & 0xFFFF;
1296                                 }
1297                         }
1298                 }
1299                 else {
1300                         /* only exclude active object when it is selected... */
1301                         if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) {
1302                                 notcol = BASACT(view_layer)->object->select_color;
1303                         }
1304
1305                         for (a = 0; a < hits; a++) {
1306                                 if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
1307                                         min = buffer[4 * a + 1];
1308                                         selcol = buffer[4 * a + 3] & 0xFFFF;
1309                                 }
1310                         }
1311                 }
1312
1313                 base = FIRSTBASE(view_layer);
1314                 while (base) {
1315                         if (BASE_SELECTABLE(base)) {
1316                                 if (base->object->select_color == selcol) break;
1317                         }
1318                         base = base->next;
1319                 }
1320                 if (base) basact = base;
1321         }
1322         else {
1323
1324                 base = startbase;
1325                 while (base) {
1326                         /* skip objects with select restriction, to prevent prematurely ending this loop
1327                          * with an un-selectable choice */
1328                         if ((base->flag & BASE_SELECTABLED) == 0) {
1329                                 base = base->next;
1330                                 if (base == NULL) base = FIRSTBASE(view_layer);
1331                                 if (base == startbase) break;
1332                         }
1333
1334                         if (BASE_SELECTABLE(base)) {
1335                                 for (a = 0; a < hits; a++) {
1336                                         if (has_bones) {
1337                                                 /* skip non-bone objects */
1338                                                 if ((buffer[4 * a + 3] & 0xFFFF0000)) {
1339                                                         if (base->object->select_color == (buffer[(4 * a) + 3] & 0xFFFF))
1340                                                                 basact = base;
1341                                                 }
1342                                         }
1343                                         else {
1344                                                 if (base->object->select_color == (buffer[(4 * a) + 3] & 0xFFFF))
1345                                                         basact = base;
1346                                         }
1347                                 }
1348                         }
1349
1350                         if (basact) break;
1351
1352                         base = base->next;
1353                         if (base == NULL) base = FIRSTBASE(view_layer);
1354                         if (base == startbase) break;
1355                 }
1356         }
1357
1358         return basact;
1359 }
1360
1361 /* mval comes from event->mval, only use within region handlers */
1362 Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
1363 {
1364         ViewContext vc;
1365         Base *basact = NULL;
1366         unsigned int buffer[MAXPICKBUF];
1367         int hits;
1368         bool do_nearest;
1369
1370         /* setup view context for argument to callbacks */
1371         view3d_operator_needs_opengl(C);
1372
1373         ED_view3d_viewcontext_init(C, &vc);
1374
1375         hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest);
1376
1377         if (hits > 0) {
1378                 const bool has_bones = selectbuffer_has_bones(buffer, hits);
1379                 basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.view_layer->object_bases.first, has_bones, do_nearest);
1380         }
1381
1382         return basact;
1383 }
1384
1385 static void deselect_all_tracks(MovieTracking *tracking)
1386 {
1387         MovieTrackingObject *object;
1388
1389         object = tracking->objects.first;
1390         while (object) {
1391                 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
1392                 MovieTrackingTrack *track = tracksbase->first;
1393
1394                 while (track) {
1395                         BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
1396
1397                         track = track->next;
1398                 }
1399
1400                 object = object->next;
1401         }
1402 }
1403
1404 /* mval is region coords */
1405 static bool ed_object_select_pick(
1406         bContext *C, const int mval[2],
1407         bool extend, bool deselect, bool toggle, bool obcenter, bool enumerate, bool object)
1408 {
1409         ViewContext vc;
1410         ARegion *ar = CTX_wm_region(C);
1411         Scene *scene = CTX_data_scene(C);
1412         ViewLayer *view_layer = CTX_data_view_layer(C);
1413         Base *base, *startbase = NULL, *basact = NULL, *oldbasact = BASACT(view_layer);
1414         const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
1415         bool is_obedit;
1416         float dist = ED_view3d_select_dist_px() * 1.3333f;
1417         bool retval = false;
1418         int hits;
1419         const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
1420
1421         /* setup view context for argument to callbacks */
1422         ED_view3d_viewcontext_init(C, &vc);
1423
1424         is_obedit = (vc.obedit != NULL);
1425         if (object) {
1426                 /* signal for view3d_opengl_select to skip editmode objects */
1427                 vc.obedit = NULL;
1428         }
1429
1430         /* In pose mode we don't want to mess with object selection. */
1431         const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE);
1432
1433         /* always start list from basact in wire mode */
1434         startbase =  FIRSTBASE(view_layer);
1435         if (BASACT(view_layer) && BASACT(view_layer)->next) startbase = BASACT(view_layer)->next;
1436
1437         /* This block uses the control key to make the object selected by its center point rather than its contents */
1438         /* in editmode do not activate */
1439         if (obcenter) {
1440
1441                 /* note; shift+alt goes to group-flush-selecting */
1442                 if (enumerate) {
1443                         basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, toggle);
1444                 }
1445                 else {
1446                         base = startbase;
1447                         while (base) {
1448                                 if (BASE_SELECTABLE(base)) {
1449                                         float screen_co[2];
1450                                         if (ED_view3d_project_float_global(
1451                                                     ar, base->object->obmat[3], screen_co,
1452                                                     V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1453                                         {
1454                                                 float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
1455                                                 if (base == BASACT(view_layer)) dist_temp += 10.0f;
1456                                                 if (dist_temp < dist) {
1457                                                         dist = dist_temp;
1458                                                         basact = base;
1459                                                 }
1460                                         }
1461                                 }
1462                                 base = base->next;
1463
1464                                 if (base == NULL) base = FIRSTBASE(view_layer);
1465                                 if (base == startbase) break;
1466                         }
1467                 }
1468 #ifdef USE_OBJECT_MODE_STRICT
1469                 if (is_obedit == false) {
1470                         if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
1471                                 if (object_mode == OB_MODE_OBJECT) {
1472                                         struct Main *bmain = CTX_data_main(C);
1473                                         ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
1474                                 }
1475                                 if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
1476                                         basact = NULL;
1477                                 }
1478                         }
1479                 }
1480 #endif
1481         }
1482         else {
1483                 unsigned int buffer[MAXPICKBUF];
1484                 bool do_nearest;
1485
1486                 // TIMEIT_START(select_time);
1487
1488                 /* if objects have posemode set, the bones are in the same selection buffer */
1489                 hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
1490
1491                 // TIMEIT_END(select_time);
1492
1493                 if (hits > 0) {
1494                         /* note: bundles are handling in the same way as bones */
1495                         const bool has_bones = selectbuffer_has_bones(buffer, hits);
1496
1497                         /* note; shift+alt goes to group-flush-selecting */
1498                         if (enumerate) {
1499                                 basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle);
1500                         }
1501                         else {
1502                                 basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
1503                         }
1504
1505 #ifdef USE_OBJECT_MODE_STRICT
1506                         if (is_obedit == false) {
1507                                 if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
1508                                         if (object_mode == OB_MODE_OBJECT) {
1509                                                 struct Main *bmain = CTX_data_main(C);
1510                                                 ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
1511                                         }
1512                                         if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
1513                                                 basact = NULL;
1514                                         }
1515                                 }
1516                         }
1517 #endif
1518
1519                         if (has_bones && basact) {
1520                                 if (basact->object->type == OB_CAMERA) {
1521                                         if (BASACT(view_layer) == basact) {
1522                                                 int i, hitresult;
1523                                                 bool changed = false;
1524
1525                                                 for (i = 0; i < hits; i++) {
1526                                                         hitresult = buffer[3 + (i * 4)];
1527
1528                                                         /* if there's bundles in buffer select bundles first,
1529                                                          * so non-camera elements should be ignored in buffer */
1530                                                         if (basact->object->select_color != (hitresult & 0xFFFF)) {
1531                                                                 continue;
1532                                                         }
1533
1534                                                         /* index of bundle is 1<<16-based. if there's no "bone" index
1535                                                          * in height word, this buffer value belongs to camera. not to bundle */
1536                                                         if (buffer[4 * i + 3] & 0xFFFF0000) {
1537                                                                 MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
1538                                                                 MovieTracking *tracking = &clip->tracking;
1539                                                                 ListBase *tracksbase;
1540                                                                 MovieTrackingTrack *track;
1541
1542                                                                 track = BKE_tracking_track_get_indexed(&clip->tracking, hitresult >> 16, &tracksbase);
1543
1544                                                                 if (TRACK_SELECTED(track) && extend) {
1545                                                                         changed = false;
1546                                                                         BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
1547                                                                 }
1548                                                                 else {
1549                                                                         int oldsel = TRACK_SELECTED(track) ? 1 : 0;
1550                                                                         if (!extend)
1551                                                                                 deselect_all_tracks(tracking);
1552
1553                                                                         BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, extend);
1554
1555                                                                         if (oldsel != (TRACK_SELECTED(track) ? 1 : 0))
1556                                                                                 changed = true;
1557                                                                 }
1558
1559                                                                 basact->flag |= BASE_SELECTED;
1560                                                                 BKE_scene_object_base_flag_sync_from_base(basact);
1561
1562                                                                 retval = true;
1563
1564                                                                 WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, track);
1565                                                                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1566
1567                                                                 break;
1568                                                         }
1569                                                 }
1570
1571                                                 if (!changed) {
1572                                                         /* fallback to regular object selection if no new bundles were selected,
1573                                                          * allows to select object parented to reconstruction object */
1574                                                         basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest);
1575                                                 }
1576                                         }
1577                                 }
1578                                 else if (ED_armature_pose_select_pick_with_buffer(
1579                                                  view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest))
1580                                 {
1581                                         /* then bone is found */
1582
1583                                         /* we make the armature selected:
1584                                          * not-selected active object in posemode won't work well for tools */
1585                                         basact->flag |= BASE_SELECTED;
1586                                         BKE_scene_object_base_flag_sync_from_base(basact);
1587
1588                                         retval = true;
1589                                         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
1590                                         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
1591
1592                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1593                                         if (BASACT(view_layer) && (BASACT(view_layer)->object->mode & OB_MODE_WEIGHT_PAINT)) {
1594                                                 /* prevent activating */
1595                                                 basact = NULL;
1596                                         }
1597
1598                                 }
1599                                 /* prevent bone selecting to pass on to object selecting */
1600                                 if (basact == BASACT(view_layer))
1601                                         basact = NULL;
1602                         }
1603                 }
1604         }
1605
1606 #ifdef USE_OBJECT_MODE_STRICT
1607         /* Disallow switching modes,
1608          * special exception for edit-mode - vertex-parent operator. */
1609         if (is_obedit == false) {
1610                 if (oldbasact && basact) {
1611                         if ((oldbasact->object->mode != basact->object->mode) &&
1612                             (oldbasact->object->mode & basact->object->mode) == 0)
1613                         {
1614                                 basact = NULL;
1615                         }
1616                 }
1617         }
1618 #endif
1619
1620         /* so, do we have something selected? */
1621         if (basact) {
1622                 retval = true;
1623
1624                 if (vc.obedit) {
1625                         /* only do select */
1626                         deselectall_except(view_layer, basact);
1627                         ED_object_base_select(basact, BA_SELECT);
1628                 }
1629                 /* also prevent making it active on mouse selection */
1630                 else if (BASE_SELECTABLE(basact)) {
1631                         if (extend) {
1632                                 ED_object_base_select(basact, BA_SELECT);
1633                         }
1634                         else if (deselect) {
1635                                 ED_object_base_select(basact, BA_DESELECT);
1636                         }
1637                         else if (toggle) {
1638                                 if (basact->flag & BASE_SELECTED) {
1639                                         if (basact == oldbasact) {
1640                                                 ED_object_base_select(basact, BA_DESELECT);
1641                                         }
1642                                 }
1643                                 else {
1644                                         ED_object_base_select(basact, BA_SELECT);
1645                                 }
1646                         }
1647                         else {
1648                                 /* When enabled, this puts other objects out of multi pose-mode. */
1649                                 if (is_pose_mode == false) {
1650                                         deselectall_except(view_layer, basact);
1651                                         ED_object_base_select(basact, BA_SELECT);
1652                                 }
1653                         }
1654
1655                         if ((oldbasact != basact) && (is_obedit == false)) {
1656                                 ED_object_base_activate(C, basact); /* adds notifier */
1657                         }
1658                 }
1659
1660                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1661         }
1662
1663         return retval;
1664 }
1665
1666 /* ********************  border and circle ************************************** */
1667
1668 typedef struct BoxSelectUserData {
1669         ViewContext *vc;
1670         const rcti *rect;
1671         const rctf *rect_fl;
1672         rctf       _rect_fl;
1673         bool select;
1674
1675         /* runtime */
1676         int pass;
1677         bool is_done;
1678         bool is_changed;
1679 } BoxSelectUserData;
1680
1681 static void view3d_userdata_boxselect_init(
1682         BoxSelectUserData *r_data,
1683         ViewContext *vc, const rcti *rect, const bool select)
1684 {
1685         r_data->vc = vc;
1686
1687         r_data->rect = rect;
1688         r_data->rect_fl = &r_data->_rect_fl;
1689         BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
1690
1691         r_data->select = select;
1692
1693         /* runtime */
1694         r_data->pass = 0;
1695         r_data->is_done = false;
1696         r_data->is_changed = false;
1697 }
1698
1699 bool edge_inside_circle(const float cent[2], float radius, const float screen_co_a[2], const float screen_co_b[2])
1700 {
1701         const float radius_squared = radius * radius;
1702         return (dist_squared_to_line_segment_v2(cent, screen_co_a, screen_co_b) < radius_squared);
1703 }
1704
1705 static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
1706 {
1707         BoxSelectUserData *data = userData;
1708
1709         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
1710                 SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
1711         }
1712 }
1713 static int do_paintvert_box_select(
1714         ViewContext *vc, rcti *rect, bool select, bool extend)
1715 {
1716         const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
1717         Mesh *me;
1718         MVert *mvert;
1719         struct ImBuf *ibuf;
1720         unsigned int *rt;
1721         int a, index;
1722         char *selar;
1723         const int size[2] = {
1724             BLI_rcti_size_x(rect) + 1,
1725             BLI_rcti_size_y(rect) + 1};
1726
1727         me = vc->obact->data;
1728
1729         if ((me == NULL) || (me->totvert == 0) || (size[0] * size[1] <= 0)) {
1730                 return OPERATOR_CANCELLED;
1731         }
1732
1733         if (extend == false && select)
1734                 paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false);
1735
1736         if (use_zbuf) {
1737                 selar = MEM_callocN(me->totvert + 1, "selar");
1738                 ED_view3d_backbuf_validate(vc);
1739
1740                 ibuf = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
1741                 rt = ibuf->rect;
1742                 glReadPixels(
1743                         rect->xmin + vc->ar->winrct.xmin,
1744                         rect->ymin + vc->ar->winrct.ymin,
1745                         size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
1746                 if (ENDIAN_ORDER == B_ENDIAN) {
1747                         IMB_convert_rgba_to_abgr(ibuf);
1748                 }
1749                 GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
1750
1751                 a = size[0] * size[1];
1752                 while (a--) {
1753                         if (*rt) {
1754                                 index = *rt;
1755                                 if (index <= me->totvert) {
1756                                         selar[index] = 1;
1757                                 }
1758                         }
1759                         rt++;
1760                 }
1761
1762                 mvert = me->mvert;
1763                 for (a = 1; a <= me->totvert; a++, mvert++) {
1764                         if (selar[a]) {
1765                                 if ((mvert->flag & ME_HIDE) == 0) {
1766                                         if (select) mvert->flag |=  SELECT;
1767                                         else        mvert->flag &= ~SELECT;
1768                                 }
1769                         }
1770                 }
1771
1772                 IMB_freeImBuf(ibuf);
1773                 MEM_freeN(selar);
1774
1775 #ifdef __APPLE__
1776                 glReadBuffer(GL_BACK);
1777 #endif
1778         }
1779         else {
1780                 BoxSelectUserData data;
1781
1782                 view3d_userdata_boxselect_init(&data, vc, rect, select);
1783
1784                 ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
1785
1786                 meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
1787         }
1788
1789         if (select == false) {
1790                 BKE_mesh_mselect_validate(me);
1791         }
1792         paintvert_flush_flags(vc->obact);
1793
1794         return OPERATOR_FINISHED;
1795 }
1796
1797 static void do_nurbs_box_select__doSelect(
1798         void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
1799 {
1800         BoxSelectUserData *data = userData;
1801         Object *obedit = data->vc->obedit;
1802         Curve *cu = (Curve *)obedit->data;
1803
1804         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
1805                 if (bp) {
1806                         bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
1807                 }
1808                 else {
1809                         if (cu->drawflag & CU_HIDE_HANDLES) {
1810                                 /* can only be (beztindex == 0) here since handles are hidden */
1811                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
1812                         }
1813                         else {
1814                                 if (beztindex == 0) {
1815                                         bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
1816                                 }
1817                                 else if (beztindex == 1) {
1818                                         bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
1819                                 }
1820                                 else {
1821                                         bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
1822                                 }
1823                         }
1824                 }
1825         }
1826 }
1827 static int do_nurbs_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
1828 {
1829         BoxSelectUserData data;
1830
1831         view3d_userdata_boxselect_init(&data, vc, rect, select);
1832
1833         if (extend == false && select) {
1834                 Curve *curve = (Curve *) vc->obedit->data;
1835                 ED_curve_deselect_all(curve->editnurb);
1836         }
1837
1838         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1839         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
1840         BKE_curve_nurb_vert_active_validate(vc->obedit->data);
1841
1842         return OPERATOR_FINISHED;
1843 }
1844
1845 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2])
1846 {
1847         BoxSelectUserData *data = userData;
1848
1849         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
1850                 bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
1851         }
1852 }
1853 static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
1854 {
1855         BoxSelectUserData data;
1856
1857         view3d_userdata_boxselect_init(&data, vc, rect, select);
1858
1859         if (extend == false && select)
1860                 ED_lattice_flags_set(vc->obedit, 0);
1861
1862         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1863         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
1864
1865         return OPERATOR_FINISHED;
1866 }
1867
1868 static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
1869 {
1870         BoxSelectUserData *data = userData;
1871
1872         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
1873                 BM_vert_select_set(data->vc->em->bm, eve, data->select);
1874         }
1875 }
1876 static void do_mesh_box_select__doSelectEdge(
1877         void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
1878 {
1879         BoxSelectUserData *data = userData;
1880
1881         if (EDBM_backbuf_check(bm_solidoffs + index)) {
1882                 if (data->pass == 0) {
1883                         if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) {
1884                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
1885                                 data->is_done = true;
1886                         }
1887                 }
1888                 else {
1889                         if (edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) {
1890                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
1891                         }
1892                 }
1893         }
1894 }
1895 static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
1896 {
1897         BoxSelectUserData *data = userData;
1898
1899         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
1900                 BM_face_select_set(data->vc->em->bm, efa, data->select);
1901         }
1902 }
1903 static int do_mesh_box_select(
1904         ViewContext *vc, rcti *rect, bool select, bool extend)
1905 {
1906         BoxSelectUserData data;
1907         ToolSettings *ts = vc->scene->toolsettings;
1908         int bbsel;
1909
1910         view3d_userdata_boxselect_init(&data, vc, rect, select);
1911
1912         if (extend == false && select)
1913                 EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
1914
1915         /* for non zbuf projections, don't change the GL state */
1916         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
1917
1918         gpuLoadMatrix(vc->rv3d->viewmat);
1919         bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1920
1921         if (ts->selectmode & SCE_SELECT_VERTEX) {
1922                 if (bbsel) {
1923                         edbm_backbuf_check_and_select_verts(vc->em, select);
1924                 }
1925                 else {
1926                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
1927                 }
1928         }
1929         if (ts->selectmode & SCE_SELECT_EDGE) {
1930                 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1931
1932                 data.pass = 0;
1933                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
1934
1935                 if (data.is_done == 0) {
1936                         data.pass = 1;
1937                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
1938                 }
1939         }
1940
1941         if (ts->selectmode & SCE_SELECT_FACE) {
1942                 if (bbsel) {
1943                         edbm_backbuf_check_and_select_faces(vc->em, select);
1944                 }
1945                 else {
1946                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
1947                 }
1948         }
1949
1950         EDBM_backbuf_free();
1951
1952         EDBM_selectmode_flush(vc->em);
1953
1954         return OPERATOR_FINISHED;
1955 }
1956
1957 static int do_meta_box_select(
1958         ViewContext *vc,
1959         const rcti *rect, bool select, bool extend)
1960 {
1961         MetaBall *mb = (MetaBall *)vc->obedit->data;
1962         MetaElem *ml;
1963         int a;
1964
1965         unsigned int buffer[MAXPICKBUF];
1966         int hits;
1967
1968         hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
1969
1970         if (extend == false && select)
1971                 BKE_mball_deselect_all(mb);
1972
1973         for (ml = mb->editelems->first; ml; ml = ml->next) {
1974                 for (a = 0; a < hits; a++) {
1975                         if (ml->selcol1 == buffer[(4 * a) + 3]) {
1976                                 ml->flag |= MB_SCALE_RAD;
1977                                 if (select) ml->flag |= SELECT;
1978                                 else ml->flag &= ~SELECT;
1979                                 break;
1980                         }
1981                         if (ml->selcol2 == buffer[(4 * a) + 3]) {
1982                                 ml->flag &= ~MB_SCALE_RAD;
1983                                 if (select) ml->flag |= SELECT;
1984                                 else ml->flag &= ~SELECT;
1985                                 break;
1986                         }
1987                 }
1988         }
1989
1990         return OPERATOR_FINISHED;
1991 }
1992
1993 static int do_armature_box_select(
1994         ViewContext *vc,
1995         const rcti *rect, bool select, bool extend)
1996 {
1997         int a;
1998
1999         unsigned int buffer[MAXPICKBUF];
2000         int hits;
2001
2002         hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
2003
2004         uint objects_len = 0;
2005         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc->view_layer, &objects_len);
2006
2007         /* clear flag we use to detect point was affected */
2008         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2009                 Object *obedit = objects[ob_index];
2010                 bArmature *arm = obedit->data;
2011                 for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
2012                         ebone->flag &= ~BONE_DONE;
2013                 }
2014         }
2015
2016         if (extend == false && select) {
2017                 ED_armature_edit_deselect_all_visible_multi(objects, objects_len);
2018         }
2019
2020         /* first we only check points inside the border */
2021         for (a = 0; a < hits; a++) {
2022                 int index = buffer[(4 * a) + 3];
2023                 if (index != -1) {
2024                         if ((index & 0xFFFF0000) == 0) {
2025                                 continue;
2026                         }
2027
2028                         EditBone *ebone;
2029                         ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone);
2030                         if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
2031                                 if (index & BONESEL_TIP) {
2032                                         ebone->flag |= BONE_DONE;
2033                                         if (select) ebone->flag |= BONE_TIPSEL;
2034                                         else ebone->flag &= ~BONE_TIPSEL;
2035                                 }
2036
2037                                 if (index & BONESEL_ROOT) {
2038                                         ebone->flag |= BONE_DONE;
2039                                         if (select) ebone->flag |= BONE_ROOTSEL;
2040                                         else ebone->flag &= ~BONE_ROOTSEL;
2041                                 }
2042                         }
2043                 }
2044         }
2045
2046         /* now we have to flush tag from parents... */
2047         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2048                 Object *obedit = objects[ob_index];
2049                 bArmature *arm = obedit->data;
2050                 for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
2051                         if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
2052                                 if (ebone->parent->flag & BONE_DONE) {
2053                                         ebone->flag |= BONE_DONE;
2054                                 }
2055                         }
2056                 }
2057         }
2058
2059         /* only select/deselect entire bones when no points where in the rect */
2060         for (a = 0; a < hits; a++) {
2061                 int index = buffer[(4 * a) + 3];
2062                 if (index != -1) {
2063                         if (index & BONESEL_BONE) {
2064                                 EditBone *ebone;
2065                                 ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone);
2066                                 if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
2067                                         if (!(ebone->flag & BONE_DONE)) {
2068                                                 if (select) {
2069                                                         ebone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
2070                                                 }
2071                                                 else {
2072                                                         ebone->flag &= ~(BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
2073                                                 }
2074                                         }
2075                                 }
2076                         }
2077                 }
2078         }
2079
2080         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2081                 Object *obedit = objects[ob_index];
2082                 bArmature *arm = obedit->data;
2083                 ED_armature_edit_sync_selection(arm->edbo);
2084         }
2085
2086         MEM_freeN(objects);
2087
2088         return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2089 }
2090
2091 /**
2092  * Compare result of 'GPU_select': 'uint[4]',
2093  * needed for when we need to align with object draw-order.
2094  */
2095 static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p)
2096 {
2097         /* 4th element is select id */
2098         uint sel_a = ((uint *)sel_a_p)[3];
2099         uint sel_b = ((uint *)sel_b_p)[3];
2100
2101 #ifdef __BIG_ENDIAN__
2102         BLI_endian_switch_uint32(&sel_a);
2103         BLI_endian_switch_uint32(&sel_b);
2104 #endif
2105
2106         if (sel_a < sel_b) {
2107                 return -1;
2108         }
2109         else if (sel_a > sel_b) {
2110                 return 1;
2111         }
2112         else {
2113                 return 0;
2114         }
2115 }
2116
2117 static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend)
2118 {
2119         unsigned int *vbuffer = NULL; /* selection buffer */
2120         int bone_only;
2121         int totobj = MAXPICKBUF; /* XXX solve later */
2122         int hits;
2123
2124         if (vc->obact && (vc->obact->mode & OB_MODE_POSE))
2125                 bone_only = 1;
2126         else
2127                 bone_only = 0;
2128
2129         if (extend == false && select) {
2130                 if (bone_only) {
2131                         FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, OB_MODE_POSE, ob_iter) {
2132                                 bArmature *arm = ob_iter->data;
2133                                 for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
2134                                         if (PBONE_VISIBLE(arm, pchan->bone)) {
2135                                                 if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) {
2136                                                         pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
2137                                                 }
2138                                         }
2139                                 }
2140                         }
2141                         FOREACH_OBJECT_IN_MODE_END;
2142                 }
2143                 else {
2144                         object_deselect_all_visible(vc->view_layer);
2145                 }
2146         }
2147
2148         /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
2149         vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer");
2150         hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL);
2151         /*
2152          * LOGIC NOTES (theeth):
2153          * The buffer and ListBase have the same relative order, which makes the selection
2154          * very simple. Loop through both data sets at the same time, if the color
2155          * is the same as the object, we have a hit and can move to the next color
2156          * and object pair, if not, just move to the next object,
2157          * keeping the same color until we have a hit.
2158          */
2159
2160         if (hits > 0) { /* no need to loop if there's no hit */
2161
2162                 /* The draw order doesn't always match the order we populate the engine, see: T51695. */
2163                 qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
2164
2165                 Base **bases = NULL;
2166                 BLI_array_declare(bases);
2167
2168                 for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
2169                         if (BASE_SELECTABLE(base)) {
2170                                 if ((base->object->select_color & 0x0000FFFF) != 0) {
2171                                         BLI_array_append(bases, base);
2172                                 }
2173                         }
2174                 }
2175
2176                 for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
2177                         Bone *bone;
2178                         Base *base = ED_armature_base_and_bone_from_select_buffer(bases, BLI_array_len(bases), *col, &bone);
2179
2180                         if (base == NULL) {
2181                                 continue;
2182                         }
2183                         /* Loop over contiguous bone hits for 'base'. */
2184                         bool changed = false;
2185                         for (; col != col_end; col += 4) {
2186                                 /* should never fail */
2187                                 if (bone != NULL) {
2188                                         if (select) {
2189                                                 if ((bone->flag & BONE_UNSELECTABLE) == 0) {
2190                                                         bone->flag |= BONE_SELECTED;
2191                                                 }
2192                                         }
2193                                         else {
2194                                                 bArmature *arm = base->object->data;
2195                                                 if ((bone->flag & BONE_UNSELECTABLE) == 0) {
2196                                                         bone->flag &= ~BONE_SELECTED;
2197                                                         if (arm->act_bone == bone)
2198                                                                 arm->act_bone = NULL;
2199                                                 }
2200                                         }
2201                                         changed = true;
2202                                 }
2203                                 else if (!bone_only) {
2204                                         ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
2205                                 }
2206
2207                                 /* Select the next bone if we're not switching bases. */
2208                                 if (col + 4 != col_end) {
2209                                         if ((base->object->select_color & 0x0000FFFF) != (col[4] & 0x0000FFFF)) {
2210                                                 break;
2211                                         }
2212
2213                                         if ((base->object->pose != NULL) && bone_only) {
2214                                                 const uint hit_bone = (col[4] & ~BONESEL_ANY) >> 16;
2215                                                 bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
2216                                                 bone = pchan ? pchan->bone : NULL;
2217                                         }
2218                                         else {
2219                                                 bone = NULL;
2220                                         }
2221                                 }
2222                         }
2223
2224                         if (changed) {
2225                                 if (base->object && (base->object->type == OB_ARMATURE)) {
2226                                         bArmature *arm = base->object->data;
2227
2228                                         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
2229
2230                                         if (vc->obact && arm && (arm->flag & ARM_HAS_VIZ_DEPS)) {
2231                                                 /* mask modifier ('armature' mode), etc. */
2232                                                 DEG_id_tag_update(&vc->obact->id, OB_RECALC_DATA);
2233                                         }
2234
2235                                         /* copy on write tag is needed (for the armature), or else no refresh happens */
2236                                         DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
2237                                 }
2238                         }
2239                 }
2240
2241                 MEM_freeN(bases);
2242
2243                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
2244         }
2245         MEM_freeN(vbuffer);
2246
2247         return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2248 }
2249
2250 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
2251 {
2252         ViewContext vc;
2253         rcti rect;
2254         bool extend;
2255         bool select;
2256
2257         int ret = OPERATOR_CANCELLED;
2258
2259         view3d_operator_needs_opengl(C);
2260
2261         /* setup view context for argument to callbacks */
2262         ED_view3d_viewcontext_init(C, &vc);
2263
2264         select = !RNA_boolean_get(op->ptr, "deselect");
2265         extend = RNA_boolean_get(op->ptr, "extend");
2266         WM_operator_properties_border_to_rcti(op, &rect);
2267
2268         if (vc.obedit) {
2269
2270                 FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.obedit->mode, ob_iter) {
2271                         ED_view3d_viewcontext_init_object(&vc, ob_iter);
2272
2273                         switch (vc.obedit->type) {
2274                                 case OB_MESH:
2275                                         vc.em = BKE_editmesh_from_object(vc.obedit);
2276                                         ret |= do_mesh_box_select(&vc, &rect, select, extend);
2277                                         if (ret & OPERATOR_FINISHED) {
2278                                                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2279                                         }
2280                                         break;
2281                                 case OB_CURVE:
2282                                 case OB_SURF:
2283                                         ret |= do_nurbs_box_select(&vc, &rect, select, extend);
2284                                         if (ret & OPERATOR_FINISHED) {
2285                                                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2286                                         }
2287                                         break;
2288                                 case OB_MBALL:
2289                                         ret |= do_meta_box_select(&vc, &rect, select, extend);
2290                                         if (ret & OPERATOR_FINISHED) {
2291                                                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2292                                         }
2293                                         break;
2294                                 case OB_ARMATURE:
2295                                         ret |= do_armature_box_select(&vc, &rect, select, extend);
2296                                         if (ret & OPERATOR_FINISHED) {
2297                                                 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
2298                                         }
2299                                         break;
2300                                 case OB_LATTICE:
2301                                         ret |= do_lattice_box_select(&vc, &rect, select, extend);
2302                                         if (ret & OPERATOR_FINISHED) {
2303                                                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2304                                         }
2305                                         break;
2306                                 default:
2307                                         assert(!"border select on incorrect object type");
2308                                         break;
2309                         }
2310                 }
2311                 FOREACH_OBJECT_IN_MODE_END;
2312         }
2313         else {  /* no editmode, unified for bones and objects */
2314                 if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
2315                         ret |= ED_sculpt_mask_box_select(C, &vc, &rect, select, extend);
2316                 }
2317                 else if (vc.obact && BKE_paint_select_face_test(vc.obact)) {
2318                         ret |= do_paintface_box_select(&vc, &rect, select, extend);
2319                 }
2320                 else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) {
2321                         ret |= do_paintvert_box_select(&vc, &rect, select, extend);
2322                 }
2323                 else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
2324                         ret |= PE_border_select(C, &rect, select, extend);
2325                 }
2326                 else { /* object mode with none active */
2327                         ret |= do_object_pose_box_select(C, &vc, &rect, select, extend);
2328                 }
2329         }
2330
2331         if (ret & OPERATOR_FINISHED) {
2332                 ret = OPERATOR_FINISHED;
2333         }
2334         else {
2335                 ret = OPERATOR_CANCELLED;
2336         }
2337
2338         return ret;
2339 }
2340
2341
2342 /* *****************Selection Operators******************* */
2343
2344 /* ****** Border Select ****** */
2345 void VIEW3D_OT_select_border(wmOperatorType *ot)
2346 {
2347         /* identifiers */
2348         ot->name = "Border Select";
2349         ot->description = "Select items using border selection";
2350         ot->idname = "VIEW3D_OT_select_border";
2351
2352         /* api callbacks */
2353         ot->invoke = WM_gesture_border_invoke;
2354         ot->exec = view3d_borderselect_exec;
2355         ot->modal = WM_gesture_border_modal;
2356         ot->poll = view3d_selectable_data;
2357         ot->cancel = WM_gesture_border_cancel;
2358
2359         /* flags */
2360         ot->flag = OPTYPE_UNDO;
2361
2362         /* rna */
2363         WM_operator_properties_gesture_border_select(ot);
2364 }
2365
2366
2367 /* mouse selection in weight paint */
2368 /* gets called via generic mouse select operator */
2369 static bool ed_wpaint_vertex_select_pick(
2370         bContext *C, const int mval[2],
2371         bool extend, bool deselect, bool toggle, Object *obact)
2372 {
2373         View3D *v3d = CTX_wm_view3d(C);
2374         const bool use_zbuf = (v3d->flag & V3D_ZBUF_SELECT) != 0;
2375
2376         Mesh *me = obact->data; /* already checked for NULL */
2377         unsigned int index = 0;
2378         MVert *mv;
2379
2380         if (ED_mesh_pick_vert(C, obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, use_zbuf)) {
2381                 mv = &me->mvert[index];
2382                 if (extend) {
2383                         mv->flag |= SELECT;
2384                 }
2385                 else if (deselect) {
2386                         mv->flag &= ~SELECT;
2387                 }
2388                 else if (toggle) {
2389                         mv->flag ^= SELECT;
2390                 }
2391                 else {
2392                         paintvert_deselect_all_visible(obact, SEL_DESELECT, false);
2393                         mv->flag |= SELECT;
2394                 }
2395
2396                 /* update mselect */
2397                 if (mv->flag & SELECT) {
2398                         BKE_mesh_mselect_active_set(me, index, ME_VSEL);
2399                 }
2400                 else {
2401                         BKE_mesh_mselect_validate(me);
2402                 }
2403
2404                 paintvert_flush_flags(obact);
2405                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2406                 return true;
2407         }
2408         return false;
2409 }
2410
2411 /* ****** Mouse Select ****** */
2412
2413
2414 static int view3d_select_exec(bContext *C, wmOperator *op)
2415 {
2416         Object *obedit = CTX_data_edit_object(C);
2417         Object *obact = CTX_data_active_object(C);
2418         bool extend = RNA_boolean_get(op->ptr, "extend");
2419         bool deselect = RNA_boolean_get(op->ptr, "deselect");
2420         bool toggle = RNA_boolean_get(op->ptr, "toggle");
2421         bool center = RNA_boolean_get(op->ptr, "center");
2422         bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
2423         /* only force object select for editmode to support vertex parenting,
2424          * or paint-select to allow pose bone select with vert/face select */
2425         bool object = (RNA_boolean_get(op->ptr, "object") &&
2426                        (obedit ||
2427                         BKE_paint_select_elem_test(obact) ||
2428                         /* so its possible to select bones in weightpaint mode (LMB select) */
2429                         (obact && (obact->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(obact))));
2430
2431         bool retval = false;
2432         int location[2];
2433
2434         RNA_int_get_array(op->ptr, "location", location);
2435
2436         view3d_operator_needs_opengl(C);
2437
2438         if (object) {
2439                 obedit = NULL;
2440                 obact = NULL;
2441
2442                 /* ack, this is incorrect but to do this correctly we would need an
2443                  * alternative editmode/objectmode keymap, this copies the functionality
2444                  * from 2.4x where Ctrl+Select in editmode does object select only */
2445                 center = false;
2446         }
2447
2448         if (obedit && object == false) {
2449                 if (obedit->type == OB_MESH)
2450                         retval = EDBM_select_pick(C, location, extend, deselect, toggle);
2451                 else if (obedit->type == OB_ARMATURE)
2452                         retval = ED_armature_edit_select_pick(C, location, extend, deselect, toggle);
2453                 else if (obedit->type == OB_LATTICE)
2454                         retval = ED_lattice_select_pick(C, location, extend, deselect, toggle);
2455                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF))
2456                         retval = ED_curve_editnurb_select_pick(C, location, extend, deselect, toggle);
2457                 else if (obedit->type == OB_MBALL)
2458                         retval = ED_mball_select_pick(C, location, extend, deselect, toggle);
2459                 else if (obedit->type == OB_FONT)
2460                         retval = ED_curve_editfont_select_pick(C, location, extend, deselect, toggle);
2461
2462         }
2463         else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT)
2464                 return PE_mouse_particles(C, location, extend, deselect, toggle);
2465         else if (obact && BKE_paint_select_face_test(obact))
2466                 retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle);
2467         else if (BKE_paint_select_vert_test(obact))
2468                 retval = ed_wpaint_vertex_select_pick(C, location, extend, deselect, toggle, obact);
2469         else
2470                 retval = ed_object_select_pick(C, location, extend, deselect, toggle, center, enumerate, object);
2471
2472         /* passthrough allows tweaks
2473          * FINISHED to signal one operator worked
2474          * */
2475         if (retval)
2476                 return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
2477         else
2478                 return OPERATOR_PASS_THROUGH;  /* nothing selected, just passthrough */
2479 }
2480
2481 static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2482 {
2483         RNA_int_set_array(op->ptr, "location", event->mval);
2484
2485         return view3d_select_exec(C, op);
2486 }
2487
2488 void VIEW3D_OT_select(wmOperatorType *ot)
2489 {
2490         PropertyRNA *prop;
2491
2492         /* identifiers */
2493         ot->name = "Activate/Select";
2494         ot->description = "Activate/select item(s)";
2495         ot->idname = "VIEW3D_OT_select";
2496
2497         /* api callbacks */
2498         ot->invoke = view3d_select_invoke;
2499         ot->exec = view3d_select_exec;
2500         ot->poll = ED_operator_view3d_active;
2501
2502         /* flags */
2503         ot->flag = OPTYPE_UNDO;
2504
2505         /* properties */
2506         WM_operator_properties_mouse_select(ot);
2507
2508         RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting, in editmode used to extend object selection");
2509         RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
2510         RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)");
2511
2512         prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX);
2513         RNA_def_property_flag(prop, PROP_HIDDEN);
2514 }
2515
2516
2517 /* -------------------- circle select --------------------------------------------- */
2518
2519 typedef struct CircleSelectUserData {
2520         ViewContext *vc;
2521         bool select;
2522         int   mval[2];
2523         float mval_fl[2];
2524         float radius;
2525         float radius_squared;
2526
2527         /* runtime */
2528         bool is_changed;
2529 } CircleSelectUserData;
2530
2531 static void view3d_userdata_circleselect_init(
2532         CircleSelectUserData *r_data,
2533         ViewContext *vc, const bool select, const int mval[2], const float rad)
2534 {
2535         r_data->vc = vc;
2536         r_data->select = select;
2537         copy_v2_v2_int(r_data->mval, mval);
2538         r_data->mval_fl[0] = mval[0];
2539         r_data->mval_fl[1] = mval[1];
2540
2541         r_data->radius = rad;
2542         r_data->radius_squared = rad * rad;
2543
2544         /* runtime */
2545         r_data->is_changed = false;
2546 }
2547
2548 static void mesh_circle_doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
2549 {
2550         CircleSelectUserData *data = userData;
2551
2552         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2553                 BM_vert_select_set(data->vc->em->bm, eve, data->select);
2554         }
2555 }
2556 static void mesh_circle_doSelectEdge(
2557         void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
2558 {
2559         CircleSelectUserData *data = userData;
2560
2561         if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
2562                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
2563         }
2564 }
2565 static void mesh_circle_doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
2566 {
2567         CircleSelectUserData *data = userData;
2568
2569         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2570                 BM_face_select_set(data->vc->em->bm, efa, data->select);
2571         }
2572 }
2573
2574 static void mesh_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2575 {
2576         ToolSettings *ts = vc->scene->toolsettings;
2577         int bbsel;
2578         CircleSelectUserData data;
2579
2580         bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
2581         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2582
2583         vc->em = BKE_editmesh_from_object(vc->obedit);
2584
2585         view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
2586
2587         if (ts->selectmode & SCE_SELECT_VERTEX) {
2588                 if (bbsel) {
2589                         edbm_backbuf_check_and_select_verts(vc->em, select);
2590                 }
2591                 else {
2592                         mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2593                 }
2594         }
2595
2596         if (ts->selectmode & SCE_SELECT_EDGE) {
2597                 if (bbsel) {
2598                         edbm_backbuf_check_and_select_edges(vc->em, select);
2599                 }
2600                 else {
2601                         mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
2602                 }
2603         }
2604
2605         if (ts->selectmode & SCE_SELECT_FACE) {
2606                 if (bbsel) {
2607                         edbm_backbuf_check_and_select_faces(vc->em, select);
2608                 }
2609                 else {
2610                         mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2611                 }
2612         }
2613
2614         EDBM_backbuf_free();
2615         EDBM_selectmode_flush(vc->em);
2616 }
2617
2618 static void paint_facesel_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2619 {
2620         Object *ob = vc->obact;
2621         Mesh *me = ob->data;
2622         bool bbsel;
2623
2624         bm_vertoffs = me->totpoly + 1; /* max index array */
2625
2626         bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
2627         if (bbsel) {
2628                 edbm_backbuf_check_and_select_tfaces(me, select);
2629                 EDBM_backbuf_free();
2630                 paintface_flush_flags(ob, SELECT);
2631         }
2632 }
2633
2634 static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
2635 {
2636         CircleSelectUserData *data = userData;
2637
2638         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2639                 SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
2640         }
2641 }
2642 static void paint_vertsel_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2643 {
2644         const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
2645         Object *ob = vc->obact;
2646         Mesh *me = ob->data;
2647         bool bbsel;
2648         /* CircleSelectUserData data = {NULL}; */ /* UNUSED */
2649
2650         if (use_zbuf) {
2651                 bm_vertoffs = me->totvert + 1; /* max index array */
2652
2653                 bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
2654                 if (bbsel) {
2655                         edbm_backbuf_check_and_select_verts_obmode(me, select);
2656                         EDBM_backbuf_free();
2657                 }
2658         }
2659         else {
2660                 CircleSelectUserData data;
2661
2662                 ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
2663
2664                 view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
2665                 meshobject_foreachScreenVert(vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2666         }
2667
2668         if (select != LEFTMOUSE) {
2669                 BKE_mesh_mselect_validate(me);
2670         }
2671         paintvert_flush_flags(ob);
2672 }
2673
2674
2675 static void nurbscurve_circle_doSelect(
2676         void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
2677 {
2678         CircleSelectUserData *data = userData;
2679         Object *obedit = data->vc->obedit;
2680         Curve *cu = (Curve *)obedit->data;
2681
2682         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2683                 if (bp) {
2684                         bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
2685                 }
2686                 else {
2687                         if (cu->drawflag & CU_HIDE_HANDLES) {
2688                                 /* can only be (beztindex == 0) here since handles are hidden */
2689                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
2690                         }
2691                         else {
2692                                 if (beztindex == 0) {
2693                                         bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
2694                                 }
2695                                 else if (beztindex == 1) {
2696                                         bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
2697                                 }
2698                                 else {
2699                                         bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
2700                                 }
2701                         }
2702                 }
2703         }
2704 }
2705 static void nurbscurve_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2706 {
2707         CircleSelectUserData data;
2708
2709         view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
2710
2711         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2712         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2713         BKE_curve_nurb_vert_active_validate(vc->obedit->data);
2714 }
2715
2716
2717 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, const float screen_co[2])
2718 {
2719         CircleSelectUserData *data = userData;
2720
2721         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2722                 bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
2723         }
2724 }
2725 static void lattice_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2726 {
2727         CircleSelectUserData data;
2728
2729         view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
2730
2731         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2732         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2733 }
2734
2735
2736 /* NOTE: pose-bone case is copied from editbone case... */
2737 static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2])
2738 {
2739         CircleSelectUserData *data = userData;
2740
2741         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2742                 if (data->select)
2743                         pchan->bone->flag |= BONE_SELECTED;
2744                 else
2745                         pchan->bone->flag &= ~BONE_SELECTED;
2746                 return 1;
2747         }
2748         return 0;
2749 }
2750 static void do_circle_select_pose__doSelectBone(
2751         void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
2752 {
2753         CircleSelectUserData *data = userData;
2754         bArmature *arm = data->vc->obact->data;
2755
2756         if (PBONE_SELECTABLE(arm, pchan->bone)) {
2757                 bool is_point_done = false;
2758                 int points_proj_tot = 0;
2759
2760                 /* project head location to screenspace */
2761                 if (screen_co_a[0] != IS_CLIPPED) {
2762                         points_proj_tot++;
2763                         if (pchan_circle_doSelectJoint(data, pchan, screen_co_a)) {
2764                                 is_point_done = true;
2765                         }
2766                 }
2767
2768                 /* project tail location to screenspace */
2769                 if (screen_co_b[0] != IS_CLIPPED) {
2770                         points_proj_tot++;
2771                         if (pchan_circle_doSelectJoint(data, pchan, screen_co_b)) {
2772                                 is_point_done = true;
2773                         }
2774                 }
2775
2776                 /* check if the head and/or tail is in the circle
2777                  * - the call to check also does the selection already
2778                  */
2779
2780                 /* only if the endpoints didn't get selected, deal with the middle of the bone too
2781                  * It works nicer to only do this if the head or tail are not in the circle,
2782                  * otherwise there is no way to circle select joints alone */
2783                 if ((is_point_done == false) && (points_proj_tot == 2) &&
2784                     edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b))
2785                 {
2786                         if (data->select) pchan->bone->flag |= BONE_SELECTED;
2787                         else              pchan->bone->flag &= ~BONE_SELECTED;
2788                         data->is_changed = true;
2789                 }
2790
2791                 data->is_changed |= is_point_done;
2792         }
2793 }
2794 static void pose_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2795 {
2796         CircleSelectUserData data;
2797
2798         view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
2799
2800         ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
2801
2802         pose_foreachScreenBone(vc, do_circle_select_pose__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2803
2804         if (data.is_changed) {
2805                 bArmature *arm = vc->obact->data;
2806
2807                 WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obact);
2808
2809                 if (arm->flag & ARM_HAS_VIZ_DEPS) {
2810                         /* mask modifier ('armature' mode), etc. */
2811                         DEG_id_tag_update(&vc->obact->id, OB_RECALC_DATA);
2812                 }
2813
2814                 /* copy on write tag is needed (for the armature), or else no refresh happens */
2815                 DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
2816         }
2817 }
2818
2819 static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], bool head)
2820 {
2821         CircleSelectUserData *data = userData;
2822
2823         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2824                 if (head) {
2825                         if (data->select)
2826                                 ebone->flag |= BONE_ROOTSEL;
2827                         else
2828                                 ebone->flag &= ~BONE_ROOTSEL;
2829                 }
2830                 else {
2831                         if (data->select)
2832                                 ebone->flag |= BONE_TIPSEL;
2833                         else
2834                                 ebone->flag &= ~BONE_TIPSEL;
2835                 }
2836                 return 1;
2837         }
2838         return 0;
2839 }
2840 static void do_circle_select_armature__doSelectBone(
2841         void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
2842 {
2843         CircleSelectUserData *data = userData;
2844         bArmature *arm = data->vc->obedit->data;
2845
2846         if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) {
2847                 bool is_point_done = false;
2848                 int points_proj_tot = 0;
2849
2850                 /* project head location to screenspace */
2851                 if (screen_co_a[0] != IS_CLIPPED) {
2852                         points_proj_tot++;
2853                         if (armature_circle_doSelectJoint(data, ebone, screen_co_a, true)) {
2854                                 is_point_done = true;
2855                         }
2856                 }
2857
2858                 /* project tail location to screenspace */
2859                 if (screen_co_b[0] != IS_CLIPPED) {
2860                         points_proj_tot++;
2861                         if (armature_circle_doSelectJoint(data, ebone, screen_co_b, false)) {
2862                                 is_point_done = true;
2863                         }
2864                 }
2865
2866                 /* check if the head and/or tail is in the circle
2867                  * - the call to check also does the selection already
2868                  */
2869
2870                 /* only if the endpoints didn't get selected, deal with the middle of the bone too
2871                  * It works nicer to only do this if the head or tail are not in the circle,
2872                  * otherwise there is no way to circle select joints alone */
2873                 if ((is_point_done == false) && (points_proj_tot == 2) &&
2874                     edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b))
2875                 {
2876                         if (data->select) ebone->flag |=  (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
2877                         else              ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
2878                         data->is_changed = true;
2879                 }
2880
2881                 data->is_changed |= is_point_done;
2882         }
2883 }
2884 static void armature_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2885 {
2886         CircleSelectUserData data;
2887         bArmature *arm = vc->obedit->data;
2888
2889         view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
2890
2891         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
2892
2893         armature_foreachScreenBone(vc, do_circle_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2894
2895         if (data.is_changed) {
2896                 ED_armature_edit_sync_selection(arm->edbo);
2897                 ED_armature_edit_validate_active(arm);
2898                 WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit);
2899         }
2900 }
2901
2902 static void do_circle_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2])
2903 {
2904         CircleSelectUserData *data = userData;
2905
2906         if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
2907                 if (data->select) ml->flag |=  SELECT;
2908                 else              ml->flag &= ~SELECT;
2909                 data->is_changed = true;
2910         }
2911 }
2912 static void mball_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2913 {
2914         CircleSelectUserData data;
2915
2916         view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
2917
2918         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
2919
2920         mball_foreachScreenElem(vc, do_circle_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
2921 }
2922
2923 /** Callbacks for circle selection in Editmode */
2924
2925 static void obedit_circle_select(
2926         ViewContext *vc, const bool select, const int mval[2], float rad)
2927 {
2928         switch (vc->obedit->type) {
2929                 case OB_MESH:
2930                         mesh_circle_select(vc, select, mval, rad);
2931                         break;
2932                 case OB_CURVE:
2933                 case OB_SURF:
2934                         nurbscurve_circle_select(vc, select, mval, rad);
2935                         break;
2936                 case OB_LATTICE:
2937                         lattice_circle_select(vc, select, mval, rad);
2938                         break;
2939                 case OB_ARMATURE:
2940                         armature_circle_select(vc, select, mval, rad);
2941                         break;
2942                 case OB_MBALL:
2943                         mball_circle_select(vc, select, mval, rad);
2944                         break;
2945                 default:
2946                         return;
2947         }
2948 }
2949
2950 static bool object_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
2951 {
2952         ViewLayer *view_layer = vc->view_layer;
2953         const float radius_squared = rad * rad;
2954         const float mval_fl[2] = {mval[0], mval[1]};
2955         bool changed = false;
2956         const int select_flag = select ? BASE_SELECTED : 0;
2957
2958
2959         Base *base;
2960         for (base = FIRSTBASE(view_layer); base; base = base->next) {
2961                 if (BASE_SELECTABLE(base) && ((base->flag & BASE_SELECTED) != select_flag)) {
2962                         float screen_co[2];
2963                         if (ED_view3d_project_float_global(
2964                                     vc->ar, base->object->obmat[3], screen_co,
2965                                     V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
2966                         {
2967                                 if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) {
2968                                         ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
2969                                         changed = true;
2970                                 }
2971                         }
2972                 }
2973         }
2974
2975         return changed;
2976 }
2977
2978 /* not a real operator, only for circle test */
2979 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
2980 {
2981         ViewContext vc;
2982         const int radius = RNA_int_get(op->ptr, "radius");
2983         const bool select = !RNA_boolean_get(op->ptr, "deselect");
2984         const int mval[2] = {RNA_int_get(op->ptr, "x"),
2985                              RNA_int_get(op->ptr, "y")};
2986
2987
2988         ED_view3d_viewcontext_init(C, &vc);
2989
2990         Object *obact = vc.obact;
2991         Object *obedit = vc.obedit;
2992
2993         if (obedit || BKE_paint_select_elem_test(obact) ||
2994             (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) )
2995         {
2996                 view3d_operator_needs_opengl(C);
2997
2998                 FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, obact->mode, ob_iter) {
2999                         ED_view3d_viewcontext_init_object(&vc, ob_iter);
3000
3001                         obact = vc.obact;
3002                         obedit = vc.obedit;
3003
3004                         if (CTX_data_edit_object(C)) {
3005                                 obedit_circle_select(&vc, select, mval, (float)radius);
3006                                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
3007                         }
3008                         else if (BKE_paint_select_face_test(obact)) {
3009                                 paint_facesel_circle_select(&vc, select, mval, (float)radius);
3010                                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
3011                         }
3012                         else if (BKE_paint_select_vert_test(obact)) {
3013                                 paint_vertsel_circle_select(&vc, select, mval, (float)radius);
3014                                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
3015                         }
3016                         else if (obact->mode & OB_MODE_POSE) {
3017                                 pose_circle_select(&vc, select, mval, (float)radius);
3018                         }
3019                         else {
3020                                 return PE_circle_select(C, select, mval, (float)radius);