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