cf82ab4f23e0f366eabdd0352a0260b19721262b
[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_layer.h"
68 #include "BKE_mball.h"
69 #include "BKE_mesh.h"
70 #include "BKE_object.h"
71 #include "BKE_paint.h"
72 #include "BKE_editmesh.h"
73 #include "BKE_scene.h"
74 #include "BKE_tracking.h"
75 #include "BKE_utildefines.h"
76
77
78 #include "BIF_gl.h"
79 #include "BIF_glutil.h"
80
81 #include "WM_api.h"
82 #include "WM_types.h"
83
84 #include "RNA_access.h"
85 #include "RNA_define.h"
86 #include "RNA_enum_types.h"
87
88 #include "ED_armature.h"
89 #include "ED_curve.h"
90 #include "ED_particle.h"
91 #include "ED_mesh.h"
92 #include "ED_object.h"
93 #include "ED_screen.h"
94 #include "ED_sculpt.h"
95 #include "ED_mball.h"
96
97 #include "UI_interface.h"
98
99 #include "GPU_draw.h"
100
101 #include "view3d_intern.h"  /* own include */
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                                 }
430                         }
431                         if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) {
432                                 do_lasso_select_pose(vc, base->object, mcords, moves, select);
433                         }
434                 }
435         }
436 }
437
438 static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
439 {
440         LassoSelectUserData *data = userData;
441
442         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
443             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
444         {
445                 BM_vert_select_set(data->vc->em->bm, eve, data->select);
446         }
447 }
448 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)
449 {
450         LassoSelectUserData *data = userData;
451
452         if (EDBM_backbuf_check(bm_solidoffs + index)) {
453                 const int x0 = screen_co_a[0];
454                 const int y0 = screen_co_a[1];
455                 const int x1 = screen_co_b[0];
456                 const int y1 = screen_co_b[1];
457
458                 if (data->pass == 0) {
459                         if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)  &&
460                             BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, IS_CLIPPED) &&
461                             BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, IS_CLIPPED))
462                         {
463                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
464                                 data->is_done = true;
465                         }
466                 }
467                 else {
468                         if (BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, IS_CLIPPED)) {
469                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
470                         }
471                 }
472         }
473 }
474 static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
475 {
476         LassoSelectUserData *data = userData;
477
478         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
479             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
480         {
481                 BM_face_select_set(data->vc->em->bm, efa, data->select);
482         }
483 }
484
485 static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
486 {
487         LassoSelectUserData data;
488         ToolSettings *ts = vc->scene->toolsettings;
489         rcti rect;
490         int bbsel;
491         
492         /* set editmesh */
493         vc->em = BKE_editmesh_from_object(vc->obedit);
494
495         BLI_lasso_boundbox(&rect, mcords, moves);
496
497         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
498
499         if (extend == false && select)
500                 EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
501
502         /* for non zbuf projections, don't change the GL state */
503         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
504
505         glLoadMatrixf(vc->rv3d->viewmat);
506         bbsel = EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
507         
508         if (ts->selectmode & SCE_SELECT_VERTEX) {
509                 if (bbsel) {
510                         edbm_backbuf_check_and_select_verts(vc->em, select);
511                 }
512                 else {
513                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
514                 }
515         }
516         if (ts->selectmode & SCE_SELECT_EDGE) {
517                 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
518                 data.pass = 0;
519                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
520
521                 if (data.is_done == false) {
522                         data.pass = 1;
523                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
524                 }
525         }
526         
527         if (ts->selectmode & SCE_SELECT_FACE) {
528                 if (bbsel) {
529                         edbm_backbuf_check_and_select_faces(vc->em, select);
530                 }
531                 else {
532                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
533                 }
534         }
535         
536         EDBM_backbuf_free();
537         EDBM_selectmode_flush(vc->em);
538 }
539
540 static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
541 {
542         LassoSelectUserData *data = userData;
543         Object *obedit = data->vc->obedit;
544         Curve *cu = (Curve *)obedit->data;
545
546         if (BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) {
547                 if (bp) {
548                         bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
549                 }
550                 else {
551                         if (cu->drawflag & CU_HIDE_HANDLES) {
552                                 /* can only be (beztindex == 0) here since handles are hidden */
553                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
554                         }
555                         else {
556                                 if (beztindex == 0) {
557                                         bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
558                                 }
559                                 else if (beztindex == 1) {
560                                         bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
561                                 }
562                                 else {
563                                         bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
564                                 }
565                         }
566                 }
567         }
568 }
569
570 static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
571 {
572         LassoSelectUserData data;
573         rcti rect;
574
575         BLI_lasso_boundbox(&rect, mcords, moves);
576
577         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
578
579         if (extend == false && select) {
580                 Curve *curve = (Curve *) vc->obedit->data;
581                 ED_curve_deselect_all(curve->editnurb);
582         }
583
584         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
585         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
586         BKE_curve_nurb_vert_active_validate(vc->obedit->data);
587 }
588
589 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
590 {
591         LassoSelectUserData *data = userData;
592
593         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
594             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
595         {
596                 bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
597         }
598 }
599 static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
600 {
601         LassoSelectUserData data;
602         rcti rect;
603
604         BLI_lasso_boundbox(&rect, mcords, moves);
605
606         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
607
608         if (extend == false && select)
609                 ED_lattice_flags_set(vc->obedit, 0);
610
611         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
612         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
613 }
614
615 static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
616 {
617         LassoSelectUserData *data = userData;
618         bArmature *arm = data->vc->obedit->data;
619
620         if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) {
621                 bool is_point_done = false;
622                 int points_proj_tot = 0;
623
624                 const int x0 = screen_co_a[0];
625                 const int y0 = screen_co_a[1];
626                 const int x1 = screen_co_b[0];
627                 const int y1 = screen_co_b[1];
628
629                 /* project head location to screenspace */
630                 if (x0 != IS_CLIPPED) {
631                         points_proj_tot++;
632                         if (BLI_rcti_isect_pt(data->rect, x0, y0) &&
633                             BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX))
634                         {
635                                 is_point_done = true;
636                                 if (data->select) ebone->flag |=  BONE_ROOTSEL;
637                                 else              ebone->flag &= ~BONE_ROOTSEL;
638                         }
639                 }
640
641                 /* project tail location to screenspace */
642                 if (x1 != IS_CLIPPED) {
643                         points_proj_tot++;
644                         if (BLI_rcti_isect_pt(data->rect, x1, y1) &&
645                             BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX))
646                         {
647                                 is_point_done = true;
648                                 if (data->select) ebone->flag |=  BONE_TIPSEL;
649                                 else              ebone->flag &= ~BONE_TIPSEL;
650                         }
651                 }
652
653                 /* if one of points selected, we skip the bone itself */
654                 if ((is_point_done == false) && (points_proj_tot == 2) &&
655                     BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX))
656                 {
657                         if (data->select) ebone->flag |=  (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
658                         else              ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
659                         data->is_changed = true;
660                 }
661
662                 data->is_changed |= is_point_done;
663         }
664 }
665
666 static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
667 {
668         LassoSelectUserData data;
669         rcti rect;
670
671         BLI_lasso_boundbox(&rect, mcords, moves);
672
673         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
674
675         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
676
677         if (extend == false && select)
678                 ED_armature_deselect_all_visible(vc->obedit);
679
680         armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
681
682         if (data.is_changed) {
683                 bArmature *arm = vc->obedit->data;
684                 ED_armature_sync_selection(arm->edbo);
685                 ED_armature_validate_active(arm);
686                 WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit);
687         }
688 }
689
690 static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2])
691 {
692         LassoSelectUserData *data = userData;
693
694         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
695             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX))
696         {
697                 if (data->select) ml->flag |=  SELECT;
698                 else              ml->flag &= ~SELECT;
699                 data->is_changed = true;
700         }
701 }
702 static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
703 {
704         LassoSelectUserData data;
705         rcti rect;
706
707         MetaBall *mb = (MetaBall *)vc->obedit->data;
708
709         if (extend == false && select)
710                 BKE_mball_deselect_all(mb);
711
712         BLI_lasso_boundbox(&rect, mcords, moves);
713
714         view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
715
716         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
717
718         mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
719 }
720
721 static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
722 {
723         LassoSelectUserData *data = userData;
724
725         if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
726             BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
727         {
728                 BKE_BIT_TEST_SET(mv->flag, data->select, SELECT);
729         }
730 }
731 static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
732 {
733         const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
734         Object *ob = vc->obact;
735         Mesh *me = ob->data;
736         rcti rect;
737
738         if (me == NULL || me->totvert == 0)
739                 return;
740
741         if (extend == false && select)
742                 paintvert_deselect_all_visible(ob, SEL_DESELECT, false);  /* flush selection at the end */
743
744         BLI_lasso_boundbox(&rect, mcords, moves);
745
746         if (use_zbuf) {
747                 bm_vertoffs = me->totvert + 1; /* max index array */
748
749                 EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
750
751                 edbm_backbuf_check_and_select_verts_obmode(me, select);
752
753                 EDBM_backbuf_free();
754         }
755         else {
756                 LassoSelectUserData data;
757
758                 view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
759
760                 ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
761
762                 meshobject_foreachScreenVert(vc, do_lasso_select_meshobject__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
763
764         }
765
766         if (select == false) {
767                 BKE_mesh_mselect_validate(me);
768         }
769         paintvert_flush_flags(ob);
770 }
771 static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
772 {
773         Object *ob = vc->obact;
774         Mesh *me = ob->data;
775         rcti rect;
776
777         if (me == NULL || me->totpoly == 0)
778                 return;
779
780         if (extend == false && select)
781                 paintface_deselect_all_visible(ob, SEL_DESELECT, false);  /* flush selection at the end */
782
783         bm_vertoffs = me->totpoly + 1; /* max index array */
784
785         BLI_lasso_boundbox(&rect, mcords, moves);
786         EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
787         
788         edbm_backbuf_check_and_select_tfaces(me, select);
789
790         EDBM_backbuf_free();
791
792         paintface_flush_flags(ob, SELECT);
793 }
794
795 #if 0
796 static void do_lasso_select_node(int mcords[][2], short moves, const bool select)
797 {
798         SpaceNode *snode = sa->spacedata.first;
799         
800         bNode *node;
801         rcti rect;
802         int node_cent[2];
803         float node_centf[2];
804         
805         BLI_lasso_boundbox(&rect, mcords, moves);
806         
807         /* store selection in temp test flag */
808         for (node = snode->edittree->nodes.first; node; node = node->next) {
809                 node_centf[0] = BLI_RCT_CENTER_X(&node->totr);
810                 node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
811                 
812                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
813                 if (BLI_rcti_isect_pt_v(&rect, node_cent) && BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])) {
814                         if (select) {
815                                 node->flag |= SELECT;
816                         }
817                         else {
818                                 node->flag &= ~SELECT;
819                         }
820                 }
821         }
822         BIF_undo_push("Lasso select nodes");
823 }
824 #endif
825
826 static void view3d_lasso_select(bContext *C, ViewContext *vc,
827                                 const int mcords[][2], short moves,
828                                 bool extend, bool select)
829 {
830         Object *ob = CTX_data_active_object(C);
831
832         if (vc->obedit == NULL) { /* Object Mode */
833                 if (BKE_paint_select_face_test(ob))
834                         do_lasso_select_paintface(vc, mcords, moves, extend, select);
835                 else if (BKE_paint_select_vert_test(ob))
836                         do_lasso_select_paintvert(vc, mcords, moves, extend, select);
837                 else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
838                         /* pass */
839                 }
840                 else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT))
841                         PE_lasso_select(C, mcords, moves, extend, select);
842                 else {
843                         do_lasso_select_objects(vc, mcords, moves, extend, select);
844                         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
845                 }
846         }
847         else { /* Edit Mode */
848                 switch (vc->obedit->type) {
849                         case OB_MESH:
850                                 do_lasso_select_mesh(vc, mcords, moves, extend, select);
851                                 break;
852                         case OB_CURVE:
853                         case OB_SURF:
854                                 do_lasso_select_curve(vc, mcords, moves, extend, select);
855                                 break;
856                         case OB_LATTICE:
857                                 do_lasso_select_lattice(vc, mcords, moves, extend, select);
858                                 break;
859                         case OB_ARMATURE:
860                                 do_lasso_select_armature(vc, mcords, moves, extend, select);
861                                 break;
862                         case OB_MBALL:
863                                 do_lasso_select_meta(vc, mcords, moves, extend, select);
864                                 break;
865                         default:
866                                 assert(!"lasso select on incorrect object type");
867                                 break;
868                 }
869
870                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data);
871         }
872 }
873
874
875 /* lasso operator gives properties, but since old code works
876  * with short array we convert */
877 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
878 {
879         ViewContext vc;
880         int mcords_tot;
881         const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
882         
883         if (mcords) {
884                 bool extend, select;
885                 view3d_operator_needs_opengl(C);
886                 
887                 /* setup view context for argument to callbacks */
888                 view3d_set_viewcontext(C, &vc);
889                 
890                 extend = RNA_boolean_get(op->ptr, "extend");
891                 select = !RNA_boolean_get(op->ptr, "deselect");
892                 view3d_lasso_select(C, &vc, mcords, mcords_tot, extend, select);
893                 
894                 MEM_freeN((void *)mcords);
895
896                 return OPERATOR_FINISHED;
897         }
898         return OPERATOR_PASS_THROUGH;
899 }
900
901 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
902 {
903         ot->name = "Lasso Select";
904         ot->description = "Select items using lasso selection";
905         ot->idname = "VIEW3D_OT_select_lasso";
906         
907         ot->invoke = WM_gesture_lasso_invoke;
908         ot->modal = WM_gesture_lasso_modal;
909         ot->exec = view3d_lasso_select_exec;
910         ot->poll = view3d_selectable_data;
911         ot->cancel = WM_gesture_lasso_cancel;
912         
913         /* flags */
914         ot->flag = OPTYPE_UNDO;
915         
916         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
917         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
918         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
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, ObjectBase *, base, selectable_bases)
1020                 {
1021                         if ((base->flag & BASE_SELECTED) != 0) {
1022                                 ED_object_base_select(base, BA_DESELECT);
1023                                 changed = true;
1024                         }
1025                 }
1026                 CTX_DATA_END;
1027         }
1028
1029         CTX_DATA_BEGIN (C, ObjectBase *, 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_object_base_activate(C, base);
1034                         ED_object_base_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(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short toggle)
1092 {
1093         short baseCount = 0;
1094         bool ok;
1095         LinkNode *linklist = NULL;
1096
1097         /* handle base->selcol */
1098         TODO_LAYER_BASE;
1099 #if 0
1100
1101         CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
1102         {
1103                 ok = false;
1104
1105                 /* two selection methods, the CTRL select uses max dist of 15 */
1106                 if (buffer) {
1107                         for (int a = 0; a < hits; a++) {
1108                                 /* index was converted */
1109                                 if (base->selcol == (buffer[(4 * a) + 3] & ~0xFFFF0000)) {
1110                                         ok = true;
1111                                         break;
1112                                 }
1113                         }
1114                 }
1115                 else {
1116                         const int dist = 15 * U.pixelsize;
1117                         if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) {
1118                                 const int delta_px[2] = {base->sx - mval[0], base->sy - mval[1]};
1119                                 if (len_manhattan_v2_int(delta_px) < dist) {
1120                                         ok = true;
1121                                 }
1122                         }
1123                 }
1124
1125                 if (ok) {
1126                         baseCount++;
1127                         BLI_linklist_prepend(&linklist, base);
1128
1129                         if (baseCount == SEL_MENU_SIZE)
1130                                 break;
1131                 }
1132         }
1133         CTX_DATA_END;
1134
1135         if (baseCount == 0) {
1136                 return NULL;
1137         }
1138         if (baseCount == 1) {
1139                 Base *base = (Base *)linklist->link;
1140                 BLI_linklist_free(linklist, NULL);
1141                 return base;
1142         }
1143         else {
1144                 /* UI, full in static array values that we later use in an enum function */
1145                 LinkNode *node;
1146                 int i;
1147
1148                 memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
1149
1150                 for (node = linklist, i = 0; node; node = node->next, i++) {
1151                         Base *base = node->link;
1152                         Object *ob = base->object;
1153                         const char *name = ob->id.name + 2;
1154
1155                         BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME - 2);
1156                         object_mouse_select_menu_data[i].icon = UI_icon_from_id(&ob->id);
1157                 }
1158
1159                 {
1160                         wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false);
1161                         PointerRNA ptr;
1162
1163                         WM_operator_properties_create_ptr(&ptr, ot);
1164                         RNA_boolean_set(&ptr, "toggle", toggle);
1165                         WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
1166                         WM_operator_properties_free(&ptr);
1167                 }
1168
1169                 BLI_linklist_free(linklist, NULL);
1170                 return NULL;
1171         }
1172 #else
1173
1174         (void)C;
1175         (void)vc,
1176         (void)buffer;
1177         (void)hits;
1178         (void)mval;
1179         (void)toggle;
1180         (void)baseCount;
1181         (void)ok;
1182         (void)linklist;
1183         return NULL;
1184 #endif
1185 }
1186
1187 static bool selectbuffer_has_bones(const unsigned int *buffer, const unsigned int hits)
1188 {
1189         unsigned int i;
1190         for (i = 0; i < hits; i++) {
1191                 if (buffer[(4 * i) + 3] & 0xFFFF0000) {
1192                         return true;
1193                 }
1194         }
1195         return false;
1196 }
1197
1198 /* utility function for mixed_bones_object_selectbuffer */
1199 static short selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const short hits15)
1200 {
1201         return hits15;
1202 }
1203
1204 static short selectbuffer_ret_hits_9(unsigned int *buffer, const short hits15, const short hits9)
1205 {
1206         const int offs = 4 * hits15;
1207         memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(unsigned int));
1208         return hits9;
1209 }
1210
1211 static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, const short hits9, const short hits5)
1212 {
1213         const int offs = 4 * hits15 + 4 * hits9;
1214         memcpy(buffer, buffer + offs, 4 * hits5  * sizeof(unsigned int));
1215         return hits5;
1216 }
1217
1218 /* we want a select buffer with bones, if there are... */
1219 /* so check three selection levels and compare */
1220 static short mixed_bones_object_selectbuffer(
1221         ViewContext *vc, unsigned int *buffer, const int mval[2],
1222         bool use_cycle, bool enumerate,
1223         bool *r_do_nearest)
1224 {
1225         rcti rect;
1226         int offs;
1227         short hits15, hits9 = 0, hits5 = 0;
1228         bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
1229         static int last_mval[2] = {-100, -100};
1230         bool do_nearest = false;
1231         View3D *v3d = vc->v3d;
1232
1233         /* define if we use solid nearest select or not */
1234         if (use_cycle) {
1235                 if (v3d->drawtype > OB_WIRE) {
1236                         do_nearest = true;
1237                         if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
1238                                 do_nearest = false;
1239                         }
1240                 }
1241                 copy_v2_v2_int(last_mval, mval);
1242         }
1243         else {
1244                 if (v3d->drawtype > OB_WIRE) {
1245                         do_nearest = true;
1246                 }
1247         }
1248
1249         if (r_do_nearest) {
1250                 *r_do_nearest = do_nearest;
1251         }
1252
1253         do_nearest = do_nearest && !enumerate;
1254
1255         BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14);
1256         hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest);
1257         if (hits15 == 1) {
1258                 return selectbuffer_ret_hits_15(buffer, hits15);
1259         }
1260         else if (hits15 > 0) {
1261                 has_bones15 = selectbuffer_has_bones(buffer, hits15);
1262
1263                 offs = 4 * hits15;
1264                 BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9);
1265                 hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
1266                 if (hits9 == 1) {
1267                         return selectbuffer_ret_hits_9(buffer, hits15, hits9);
1268                 }
1269                 else if (hits9 > 0) {
1270                         has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
1271
1272                         offs += 4 * hits9;
1273                         BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5);
1274                         hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
1275                         if (hits5 == 1) {
1276                                 return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1277                         }
1278                         else if (hits5 > 0) {
1279                                 has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
1280                         }
1281                 }
1282
1283                 if      (has_bones5)  return selectbuffer_ret_hits_5(buffer,  hits15, hits9, hits5);
1284                 else if (has_bones9)  return selectbuffer_ret_hits_9(buffer,  hits15, hits9);
1285                 else if (has_bones15) return selectbuffer_ret_hits_15(buffer, hits15);
1286                 
1287                 if      (hits5 > 0) return selectbuffer_ret_hits_5(buffer,  hits15, hits9, hits5);
1288                 else if (hits9 > 0) return selectbuffer_ret_hits_9(buffer,  hits15, hits9);
1289                 else                return selectbuffer_ret_hits_15(buffer, hits15);
1290         }
1291         
1292         return 0;
1293 }
1294
1295 /* returns basact */
1296 static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits,
1297                                       Base *startbase, bool has_bones, bool do_nearest)
1298 {
1299         Scene *scene = vc->scene;
1300         View3D *v3d = vc->v3d;
1301         Base *base, *basact = NULL;
1302         int a;
1303         
1304         if (do_nearest) {
1305                 unsigned int min = 0xFFFFFFFF;
1306                 int selcol = 0, notcol = 0;
1307                 
1308                 
1309                 if (has_bones) {
1310                         /* we skip non-bone hits */
1311                         for (a = 0; a < hits; a++) {
1312                                 if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000) ) {
1313                                         min = buffer[4 * a + 1];
1314                                         selcol = buffer[4 * a + 3] & 0xFFFF;
1315                                 }
1316                         }
1317                 }
1318                 else {
1319                         /* only exclude active object when it is selected... */
1320                         if (BASACT && (BASACT->flag & SELECT) && hits > 1) notcol = BASACT->selcol;
1321                         
1322                         for (a = 0; a < hits; a++) {
1323                                 if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
1324                                         min = buffer[4 * a + 1];
1325                                         selcol = buffer[4 * a + 3] & 0xFFFF;
1326                                 }
1327                         }
1328                 }
1329                 
1330                 base = FIRSTBASE;
1331                 while (base) {
1332                         if (BASE_SELECTABLE(v3d, base)) {
1333                                 if (base->selcol == selcol) break;
1334                         }
1335                         base = base->next;
1336                 }
1337                 if (base) basact = base;
1338         }
1339         else {
1340                 
1341                 base = startbase;
1342                 while (base) {
1343                         /* skip objects with select restriction, to prevent prematurely ending this loop
1344                          * with an un-selectable choice */
1345                         if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1346                                 base = base->next;
1347                                 if (base == NULL) base = FIRSTBASE;
1348                                 if (base == startbase) break;
1349                         }
1350                         
1351                         if (BASE_SELECTABLE(v3d, base)) {
1352                                 for (a = 0; a < hits; a++) {
1353                                         if (has_bones) {
1354                                                 /* skip non-bone objects */
1355                                                 if ((buffer[4 * a + 3] & 0xFFFF0000)) {
1356                                                         if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF))
1357                                                                 basact = base;
1358                                                 }
1359                                         }
1360                                         else {
1361                                                 if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF))
1362                                                         basact = base;
1363                                         }
1364                                 }
1365                         }
1366                         
1367                         if (basact) break;
1368                         
1369                         base = base->next;
1370                         if (base == NULL) base = FIRSTBASE;
1371                         if (base == startbase) break;
1372                 }
1373         }
1374         
1375         return basact;
1376 }
1377
1378 /* mval comes from event->mval, only use within region handlers */
1379 Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
1380 {
1381         ViewContext vc;
1382         Base *basact = NULL;
1383         unsigned int buffer[MAXPICKBUF];
1384         int hits;
1385         bool do_nearest;
1386         
1387         /* setup view context for argument to callbacks */
1388         view3d_operator_needs_opengl(C);
1389         view3d_set_viewcontext(C, &vc);
1390         
1391         hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest);
1392         
1393         if (hits > 0) {
1394                 const bool has_bones = selectbuffer_has_bones(buffer, hits);
1395                 basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest);
1396         }
1397         
1398         return basact;
1399 }
1400
1401 static void deselect_all_tracks(MovieTracking *tracking)
1402 {
1403         MovieTrackingObject *object;
1404
1405         object = tracking->objects.first;
1406         while (object) {
1407                 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
1408                 MovieTrackingTrack *track = tracksbase->first;
1409
1410                 while (track) {
1411                         BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
1412
1413                         track = track->next;
1414                 }
1415
1416                 object = object->next;
1417         }
1418 }
1419
1420 /* mval is region coords */
1421 static bool ed_object_select_pick(
1422         bContext *C, const int mval[2],
1423         bool extend, bool deselect, bool toggle, bool obcenter, bool enumerate, bool object)
1424 {
1425         ViewContext vc;
1426         ARegion *ar = CTX_wm_region(C);
1427         View3D *v3d = CTX_wm_view3d(C);
1428         Scene *scene = CTX_data_scene(C);
1429         Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL;
1430         bool is_obedit;
1431         float dist = ED_view3d_select_dist_px() * 1.3333f;
1432         bool retval = false;
1433         short hits;
1434         const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
1435
1436         
1437         /* setup view context for argument to callbacks */
1438         view3d_set_viewcontext(C, &vc);
1439
1440         is_obedit = (vc.obedit != NULL);
1441         if (object) {
1442                 /* signal for view3d_opengl_select to skip editmode objects */
1443                 vc.obedit = NULL;
1444         }
1445         
1446         /* always start list from basact in wire mode */
1447         startbase =  FIRSTBASE;
1448         if (BASACT && BASACT->next) startbase = BASACT->next;
1449         
1450         /* This block uses the control key to make the object selected by its center point rather than its contents */
1451         /* in editmode do not activate */
1452         if (obcenter) {
1453                 
1454                 /* note; shift+alt goes to group-flush-selecting */
1455                 if (enumerate) {
1456                         basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, toggle);
1457                 }
1458                 else {
1459                         base = startbase;
1460                         while (base) {
1461                                 if (BASE_SELECTABLE(v3d, base)) {
1462                                         float screen_co[2];
1463                                         if (ED_view3d_project_float_global(ar, base->object->obmat[3], screen_co,
1464                                                                            V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
1465                                         {
1466                                                 float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
1467                                                 if (base == BASACT) dist_temp += 10.0f;
1468                                                 if (dist_temp < dist) {
1469                                                         dist = dist_temp;
1470                                                         basact = base;
1471                                                 }
1472                                         }
1473                                 }
1474                                 base = base->next;
1475                                 
1476                                 if (base == NULL) base = FIRSTBASE;
1477                                 if (base == startbase) break;
1478                         }
1479                 }
1480         }
1481         else {
1482                 unsigned int buffer[MAXPICKBUF];
1483                 bool do_nearest;
1484
1485                 /* if objects have posemode set, the bones are in the same selection buffer */
1486                 
1487                 hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
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         short hits;
1926
1927         hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
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         short hits;
1960
1961         hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
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         short 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, false);
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_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
2141         WM_operator_properties_border_to_rcti(op, &rect);
2142         extend = RNA_boolean_get(op->ptr, "extend");
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_border_select_invoke;
2218         ot->exec = view3d_borderselect_exec;
2219         ot->modal = WM_border_select_modal;
2220         ot->poll = view3d_selectable_data;
2221         ot->cancel = WM_border_select_cancel;
2222         
2223         /* flags */
2224         ot->flag = OPTYPE_UNDO;
2225         
2226         /* rna */
2227         WM_operator_properties_gesture_border(ot, true);
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 short 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 short armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], short 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 int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
2839         const bool select = (gesture_mode == GESTURE_MODAL_SELECT);
2840         const int mval[2] = {RNA_int_get(op->ptr, "x"),
2841                              RNA_int_get(op->ptr, "y")};
2842
2843         if (CTX_data_edit_object(C) || BKE_paint_select_elem_test(obact) ||
2844             (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) )
2845         {
2846                 ViewContext vc;
2847                 
2848                 view3d_operator_needs_opengl(C);
2849                 
2850                 view3d_set_viewcontext(C, &vc);
2851
2852                 if (CTX_data_edit_object(C)) {
2853                         obedit_circle_select(&vc, select, mval, (float)radius);
2854                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2855                 }
2856                 else if (BKE_paint_select_face_test(obact)) {
2857                         paint_facesel_circle_select(&vc, select, mval, (float)radius);
2858                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2859                 }
2860                 else if (BKE_paint_select_vert_test(obact)) {
2861                         paint_vertsel_circle_select(&vc, select, mval, (float)radius);
2862                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2863                 }
2864                 else if (obact->mode & OB_MODE_POSE)
2865                         pose_circle_select(&vc, select, mval, (float)radius);
2866                 else
2867                         return PE_circle_select(C, select, mval, (float)radius);
2868         }
2869         else if (obact && obact->mode & OB_MODE_SCULPT) {
2870                 return OPERATOR_CANCELLED;
2871         }
2872         else {
2873                 ViewContext vc;
2874                 view3d_set_viewcontext(C, &vc);
2875
2876                 if (object_circle_select(&vc, select, mval, (float)radius)) {
2877                         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
2878                 }
2879         }
2880         
2881         return OPERATOR_FINISHED;
2882 }
2883
2884 void VIEW3D_OT_select_circle(wmOperatorType *ot)
2885 {
2886         ot->name = "Circle Select";
2887         ot->description = "Select items using circle selection";
2888         ot->idname = "VIEW3D_OT_select_circle";
2889         
2890         ot->invoke = WM_gesture_circle_invoke;
2891         ot->modal = WM_gesture_circle_modal;
2892         ot->exec = view3d_circle_select_exec;
2893         ot->poll = view3d_selectable_data;
2894         ot->cancel = WM_gesture_circle_cancel;
2895         
2896         /* flags */
2897         ot->flag = OPTYPE_UNDO;
2898         
2899         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2900         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2901         RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
2902         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2903 }