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