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