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