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