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