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