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