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