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