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