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