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