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