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