4a702665c8858b8d6eb28c1d8ebda7c445f0a47e
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_curve_types.h"
37 #include "DNA_camera_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_userdef_types.h"
47 #include "DNA_view3d_types.h"
48 #include "DNA_world_types.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_arithb.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_rand.h"
56
57 #include "BKE_action.h"
58 #include "BKE_context.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_object.h"
61 #include "BKE_global.h"
62 #include "BKE_scene.h"
63 #include "BKE_screen.h"
64 #include "BKE_utildefines.h"
65
66 #include "RE_pipeline.h"        // make_stars
67
68 #include "BIF_gl.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_retopo.h"
82 #include "ED_screen.h"
83 #include "ED_types.h"
84 #include "ED_util.h"
85 #include "ED_mball.h"
86
87 #include "UI_interface.h"
88 #include "UI_resources.h"
89 #include "UI_view2d.h"
90
91 #include "PIL_time.h" /* smoothview */
92
93 #include "view3d_intern.h"      // own include
94
95
96 void view3d_set_viewcontext(bContext *C, ViewContext *vc)
97 {
98         memset(vc, 0, sizeof(ViewContext));
99         vc->ar= CTX_wm_region(C);
100         vc->scene= CTX_data_scene(C);
101         vc->v3d= CTX_wm_view3d(C);
102         vc->rv3d= vc->ar->regiondata;
103         vc->obact= CTX_data_active_object(C);
104         vc->obedit= CTX_data_edit_object(C); 
105 }
106
107 void view3d_get_view_aligned_coordinate(ViewContext *vc, float *fp, short mval[2])
108 {
109         float dvec[3];
110         short mx, my;
111         
112         mx= mval[0];
113         my= mval[1];
114         
115         project_short_noclip(vc->ar, fp, mval);
116         
117         initgrabz(vc->rv3d, fp[0], fp[1], fp[2]);
118         
119         if(mval[0]!=IS_CLIPPED) {
120                 window_to_3d_delta(vc->ar, dvec, mval[0]-mx, mval[1]-my);
121                 VecSubf(fp, fp, dvec);
122         }
123 }
124
125 void view3d_get_transformation(ViewContext *vc, Object *ob, bglMats *mats)
126 {
127         float cpy[4][4];
128         int i, j;
129
130         Mat4MulMat4(cpy, vc->rv3d->viewmat, ob->obmat);
131
132         for(i = 0; i < 4; ++i) {
133                 for(j = 0; j < 4; ++j) {
134                         mats->projection[i*4+j] = vc->rv3d->winmat[i][j];
135                         mats->modelview[i*4+j] = cpy[i][j];
136                 }
137         }
138
139         mats->viewport[0] = vc->ar->winrct.xmin;
140         mats->viewport[1] = vc->ar->winrct.ymin;
141         mats->viewport[2] = vc->ar->winx;
142         mats->viewport[3] = vc->ar->winy;       
143 }
144
145 /* ********************** view3d_select: selection manipulations ********************* */
146
147 /* XXX to solve *************** */
148 static void BIF_undo_push() {}
149 /* XXX end ********************* */
150
151 /* local prototypes */
152
153 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
154 {
155         EditVert *eve;
156         int index= em_wireoffs;
157
158         for(eve= em->verts.first; eve; eve= eve->next, index++) {
159                 if(eve->h==0) {
160                         if(EM_check_backbuf(index)) {
161                                 eve->f = select?(eve->f|1):(eve->f&~1);
162                         }
163                 }
164         }
165 }
166
167 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
168 {
169         EditEdge *eed;
170         int index= em_solidoffs;
171
172         for(eed= em->edges.first; eed; eed= eed->next, index++) {
173                 if(eed->h==0) {
174                         if(EM_check_backbuf(index)) {
175                                 EM_select_edge(eed, select);
176                         }
177                 }
178         }
179 }
180
181 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
182 {
183         EditFace *efa;
184         int index= 1;
185
186         for(efa= em->faces.first; efa; efa= efa->next, index++) {
187                 if(efa->h==0) {
188                         if(EM_check_backbuf(index)) {
189                                 EM_select_face_fgon(em, efa, select);
190                         }
191                 }
192         }
193 }
194
195 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
196 {
197         MFace *mface = me->mface;
198         int a;
199
200         if (mface) {
201                 for(a=1; a<=me->totface; a++, mface++) {
202                         if(EM_check_backbuf(a)) {
203                                 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
204                         }
205                 }
206         }
207 }
208
209 void arrows_move_cursor(unsigned short event)
210 {
211 #if 0
212         short mval[2];
213
214         getmouseco_sc(mval);
215
216         if(event==UPARROWKEY) {
217                 warp_pointer(mval[0], mval[1]+1);
218         } else if(event==DOWNARROWKEY) {
219                 warp_pointer(mval[0], mval[1]-1);
220         } else if(event==LEFTARROWKEY) {
221                 warp_pointer(mval[0]-1, mval[1]);
222         } else if(event==RIGHTARROWKEY) {
223                 warp_pointer(mval[0]+1, mval[1]);
224         }
225 #endif
226 }
227
228
229 /* *********************** GESTURE AND LASSO ******************* */
230
231 /* helper also for borderselect */
232 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
233 {
234         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
235 }
236
237 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
238 {
239         int d1, d2, d3, d4;
240         
241         /* check points in rect */
242         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
243         
244         /* check points completely out rect */
245         if(x1<rect->xmin && x2<rect->xmin) return 0;
246         if(x1>rect->xmax && x2>rect->xmax) return 0;
247         if(y1<rect->ymin && y2<rect->ymin) return 0;
248         if(y1>rect->ymax && y2>rect->ymax) return 0;
249         
250         /* simple check lines intersecting. */
251         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
252         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
253         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
254         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
255         
256         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
257         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
258         
259         return 1;
260 }
261
262
263 #define MOVES_GESTURE 50
264 #define MOVES_LASSO 500
265
266 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
267 {
268         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
269         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
270         int a;
271         short *p1, *p2;
272         
273         if(sx==IS_CLIPPED)
274                 return 0;
275         
276         p1= mcords[moves-1];
277         p2= mcords[0];
278         
279         /* first vector */
280         fp1[0]= (float)(p1[0]-sx);
281         fp1[1]= (float)(p1[1]-sy);
282         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
283         fp1[0]/= len;
284         fp1[1]/= len;
285         
286         for(a=0; a<moves; a++) {
287                 /* second vector */
288                 fp2[0]= (float)(p2[0]-sx);
289                 fp2[1]= (float)(p2[1]-sy);
290                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
291                 fp2[0]/= len;
292                 fp2[1]/= len;
293                 
294                 /* dot and angle and cross */
295                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
296                 ang= fabs(saacos(dot));
297
298                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
299                 
300                 if(cross<0.0) angletot-= ang;
301                 else angletot+= ang;
302                 
303                 /* circulate */
304                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
305                 p1= p2;
306                 p2= mcords[a+1];
307         }
308         
309         if( fabs(angletot) > 4.0 ) return 1;
310         return 0;
311 }
312
313 /* edge version for lasso select. we assume boundbox check was done */
314 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
315 {
316         short v1[2], v2[2];
317         int a;
318
319         if(x0==IS_CLIPPED || x1==IS_CLIPPED)
320                 return 0;
321         
322         v1[0] = x0, v1[1] = y0;
323         v2[0] = x1, v2[1] = y1;
324
325         /* check points in lasso */
326         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
327         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
328         
329         /* no points in lasso, so we have to intersect with lasso edge */
330         
331         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
332         for(a=0; a<moves-1; a++) {
333                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
334         }
335         
336         return 0;
337 }
338
339
340 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
341    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
342 */
343 static void do_lasso_select_pose(ViewContext *vc, short mcords[][2], short moves, short select)
344 {
345         Object *ob= vc->obact;
346         bPoseChannel *pchan;
347         float vec[3];
348         short sco1[2], sco2[2];
349         
350         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
351         
352         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
353                 VECCOPY(vec, pchan->pose_head);
354                 Mat4MulVecfl(ob->obmat, vec);
355                 project_short(vc->ar, vec, sco1);
356                 VECCOPY(vec, pchan->pose_tail);
357                 Mat4MulVecfl(ob->obmat, vec);
358                 project_short(vc->ar, vec, sco2);
359                 
360                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
361                         if(select) pchan->bone->flag |= BONE_SELECTED;
362                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
363                 }
364         }
365 }
366
367
368 static void do_lasso_select_objects(ViewContext *vc, short mcords[][2], short moves, short select)
369 {
370         Base *base;
371         
372         for(base= vc->scene->base.first; base; base= base->next) {
373                 if(base->lay & vc->v3d->lay) {
374                         project_short(vc->ar, base->object->obmat[3], &base->sx);
375                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
376                                 
377                                 if(select) ED_base_object_select(base, BA_SELECT);
378                                 else ED_base_object_select(base, BA_DESELECT);
379                                 base->object->flag= base->flag;
380                         }
381                         if(base->object->flag & OB_POSEMODE) {
382                                 do_lasso_select_pose(vc, mcords, moves, select);
383                         }
384                 }
385         }
386 }
387
388 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
389 {
390         short a;
391         
392         rect->xmin= rect->xmax= mcords[0][0];
393         rect->ymin= rect->ymax= mcords[0][1];
394         
395         for(a=1; a<moves; a++) {
396                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
397                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
398                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
399                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
400         }
401 }
402
403 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
404 {
405         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
406
407         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
408                 eve->f = data->select?(eve->f|1):(eve->f&~1);
409         }
410 }
411 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
412 {
413         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
414
415         if (EM_check_backbuf(em_solidoffs+index)) {
416                 if (data->pass==0) {
417                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
418                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
419                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
420                                 EM_select_edge(eed, data->select);
421                                 data->done = 1;
422                         }
423                 } else {
424                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
425                                 EM_select_edge(eed, data->select);
426                         }
427                 }
428         }
429 }
430 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
431 {
432         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
433
434         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
435                 EM_select_face_fgon(data->vc.em, efa, data->select);
436         }
437 }
438
439 static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
440 {
441         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
442         ToolSettings *ts= vc->scene->toolsettings;
443         rcti rect;
444         int bbsel;
445         
446         lasso_select_boundbox(&rect, mcords, moves);
447         
448         /* set editmesh */
449         vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
450
451         data.vc= *vc;
452         data.rect = &rect;
453         data.mcords = mcords;
454         data.moves = moves;
455         data.select = select;
456         data.done = 0;
457         data.pass = 0;
458
459         bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
460         
461         if(ts->selectmode & SCE_SELECT_VERTEX) {
462                 if (bbsel) {
463                         EM_backbuf_checkAndSelectVerts(vc->em, select);
464                 } else {
465                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
466                 }
467         }
468         if(ts->selectmode & SCE_SELECT_EDGE) {
469                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
470
471                 data.pass = 0;
472                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
473
474                 if (data.done==0) {
475                         data.pass = 1;
476                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
477                 }
478         }
479         
480         if(ts->selectmode & SCE_SELECT_FACE) {
481                 if (bbsel) {
482                         EM_backbuf_checkAndSelectFaces(vc->em, select);
483                 } else {
484                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
485                 }
486         }
487         
488         EM_free_backbuf();
489         EM_selectmode_flush(vc->em);    
490 }
491
492 #if 0
493 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
494 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
495 {
496         EditFace *efa;
497         MTFace *tf;
498         int screenUV[2], nverts, i, ok = 1;
499         rcti rect;
500         
501         lasso_select_boundbox(&rect, mcords, moves);
502         
503         if (draw_uvs_face_check()) { /* Face Center Sel */
504                 float cent[2];
505                 ok = 0;
506                 for (efa= em->faces.first; efa; efa= efa->next) {
507                         /* assume not touched */
508                         efa->tmp.l = 0;
509                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
510                         if ((select) != (simaFaceSel_Check(efa, tf))) {
511                                 uv_center(tf->uv, cent, (void *)efa->v4);
512                                 uvco_to_areaco_noclip(cent, screenUV);
513                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
514                                         efa->tmp.l = ok = 1;
515                                 }
516                         }
517                 }
518                 /* (de)selects all tagged faces and deals with sticky modes */
519                 if (ok)
520                         uvface_setsel__internal(select);
521                 
522         } else { /* Vert Sel*/
523                 for (efa= em->faces.first; efa; efa= efa->next) {
524                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
525                         if (simaFaceDraw_Check(efa, tf)) {              
526                                 nverts= efa->v4? 4: 3;
527                                 for(i=0; i<nverts; i++) {
528                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
529                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
530                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
531                                                         if (select) {
532                                                                 simaUVSel_Set(efa, tf, i);
533                                                         } else {
534                                                                 simaUVSel_UnSet(efa, tf, i);
535                                                         }
536                                                 }
537                                         }
538                                 }
539                         }
540                 }
541         }
542         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
543                 if (select) EM_select_flush(vc->em);
544                 else            EM_deselect_flush(vc->em);
545         }
546 }
547 #endif
548
549 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
550 {
551         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
552
553         if (lasso_inside(data->mcords, data->moves, x, y)) {
554                 if (bp) {
555                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
556                 } else {
557                         if (G.f & G_HIDDENHANDLES) {
558                                 /* can only be beztindex==0 here since handles are hidden */
559                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
560                         } else {
561                                 if (beztindex==0) {
562                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
563                                 } else if (beztindex==1) {
564                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
565                                 } else {
566                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
567                                 }
568                         }
569                 }
570         }
571 }
572
573 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
574 {
575         struct { short (*mcords)[2]; short moves; short select; } data;
576
577         /* set vc->editnurb */
578         data.mcords = mcords;
579         data.moves = moves;
580         data.select = select;
581
582         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
583 }
584
585 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
586 {
587         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
588
589         if (lasso_inside(data->mcords, data->moves, x, y)) {
590                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
591         }
592 }
593 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
594 {
595         struct { short (*mcords)[2]; short moves; short select; } data;
596
597         /* set editdata in vc */
598         data.mcords = mcords;
599         data.moves = moves;
600         data.select = select;
601
602         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
603 }
604
605 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
606 {
607         bArmature *arm= vc->obedit->data;
608         EditBone *ebone;
609         float vec[3];
610         short sco1[2], sco2[2], didpoint;
611         
612         /* set editdata in vc */
613         
614         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
615
616                 VECCOPY(vec, ebone->head);
617                 Mat4MulVecfl(vc->obedit->obmat, vec);
618                 project_short(vc->ar, vec, sco1);
619                 VECCOPY(vec, ebone->tail);
620                 Mat4MulVecfl(vc->obedit->obmat, vec);
621                 project_short(vc->ar, vec, sco2);
622                 
623                 didpoint= 0;
624                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
625                         if(select) ebone->flag |= BONE_ROOTSEL;
626                         else ebone->flag &= ~BONE_ROOTSEL;
627                         didpoint= 1;
628                 }
629                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
630                    if(select) ebone->flag |= BONE_TIPSEL;
631                    else ebone->flag &= ~BONE_TIPSEL;
632                    didpoint= 1;
633                 }
634                 /* if one of points selected, we skip the bone itself */
635                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
636                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
637                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
638                 }
639         }
640 }
641
642 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
643 {
644         Object *ob= vc->obact;
645         Mesh *me= ob?ob->data:NULL;
646         rcti rect;
647         
648         if(me==NULL || me->mtface==NULL) return;
649         if(me->totface==0) return;
650         
651         em_vertoffs= me->totface+1;     /* max index array */
652         
653         lasso_select_boundbox(&rect, mcords, moves);
654         EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
655         
656         EM_backbuf_checkAndSelectTFaces(me, select);
657         
658         EM_free_backbuf();
659         
660 // XXX  object_tface_flags_changed(ob, 0);
661 }
662
663 #if 0
664 static void do_lasso_select_node(short mcords[][2], short moves, short select)
665 {
666         SpaceNode *snode = sa->spacedata.first;
667         
668         bNode *node;
669         rcti rect;
670         short node_cent[2];
671         float node_centf[2];
672         
673         lasso_select_boundbox(&rect, mcords, moves);
674         
675         /* store selection in temp test flag */
676         for(node= snode->edittree->nodes.first; node; node= node->next) {
677                 
678                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
679                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
680                 
681                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
682                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
683                         if (select) {
684                                 node->flag |= SELECT;
685                         } else {
686                                 node->flag &= ~SELECT;
687                         }
688                 }
689         }
690         BIF_undo_push("Lasso select nodes");
691 }
692 #endif
693
694 void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short moves, short select)
695 {
696         if(vc->obedit==NULL) {
697                 if(FACESEL_PAINT_TEST)
698                         do_lasso_select_facemode(vc, mcords, moves, select);
699                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
700                         ;
701                 else if(G.f & G_PARTICLEEDIT)
702                         PE_lasso_select(C, mcords, moves, select);
703                 else  
704                         do_lasso_select_objects(vc, mcords, moves, select);
705         }
706         else if(vc->obedit->type==OB_MESH) {
707                 do_lasso_select_mesh(vc, mcords, moves, select);
708         } else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF) 
709                 do_lasso_select_curve(vc, mcords, moves, select);
710         else if(vc->obedit->type==OB_LATTICE) 
711                 do_lasso_select_lattice(vc, mcords, moves, select);
712         else if(vc->obedit->type==OB_ARMATURE)
713                 do_lasso_select_armature(vc, mcords, moves, select);
714
715         BIF_undo_push("Lasso select");
716         
717 }
718
719
720 /* lasso operator gives properties, but since old code works
721    with short array we convert */
722 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
723 {
724         ViewContext vc;
725         int select, i= 0;
726         short mcords[1024][2];
727
728         RNA_BEGIN(op->ptr, itemptr, "path") {
729                 float loc[2];
730                 
731                 RNA_float_get_array(&itemptr, "loc", loc);
732                 mcords[i][0]= (short)loc[0];
733                 mcords[i][1]= (short)loc[1];
734                 i++;
735                 if(i>=1024) break;
736         }
737         RNA_END;
738         
739         if(i>1) {
740                 view3d_operator_needs_opengl(C);
741                 
742                 /* setup view context for argument to callbacks */
743                 view3d_set_viewcontext(C, &vc);
744                 
745                 select= !RNA_boolean_get(op->ptr, "deselect");
746                 view3d_lasso_select(C, &vc, mcords, i, select);
747                 
748                 return OPERATOR_FINISHED;
749         }
750         return OPERATOR_PASS_THROUGH;
751 }
752
753 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
754 {
755         ot->name= "Lasso Select";
756         ot->idname= "VIEW3D_OT_select_lasso";
757         
758         ot->invoke= WM_gesture_lasso_invoke;
759         ot->modal= WM_gesture_lasso_modal;
760         ot->exec= view3d_lasso_select_exec;
761         ot->poll= WM_operator_winactive;
762         
763         /* flags */
764         ot->flag= OPTYPE_UNDO;
765         
766         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
767         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items.");
768 }
769
770
771 /* ************************************************* */
772
773 #if 0
774 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
775 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
776 {
777         Base *base;
778         unsigned int *bufmin,*bufmax;
779         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
780         unsigned int retval=0;
781         
782         base= LASTBASE;
783         if(base==0) return 0;
784         maxob= base->selcol;
785
786         aantal= (size-1)/2;
787         rc= 0;
788
789         dirvec[0][0]= 1;
790         dirvec[0][1]= 0;
791         dirvec[1][0]= 0;
792         dirvec[1][1]= -size;
793         dirvec[2][0]= -1;
794         dirvec[2][1]= 0;
795         dirvec[3][0]= 0;
796         dirvec[3][1]= size;
797
798         bufmin= buf;
799         bufmax= buf+ size*size;
800         buf+= aantal*size+ aantal;
801
802         for(tel=1;tel<=size;tel++) {
803
804                 for(a=0;a<2;a++) {
805                         for(b=0;b<tel;b++) {
806
807                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
808                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
809                                 
810                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
811
812                                 if(buf<bufmin || buf>=bufmax) return retval;
813                         }
814                         rc++;
815                         rc &= 3;
816                 }
817         }
818         return retval;
819 }
820 #endif
821
822 /* ************************** mouse select ************************* */
823
824
825 /* The max number of menu items in an object select menu */
826 #define SEL_MENU_SIZE   22
827
828 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
829 {
830         Base *base;
831         
832         for(base= FIRSTBASE; base; base= base->next) {
833                 if (base->flag & SELECT) {
834                         if(b!=base) {
835                                 ED_base_object_select(base, BA_DESELECT);
836                         }
837                 }
838         }
839 }
840
841 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
842 {
843         Scene *scene= vc->scene;
844         View3D *v3d= vc->v3d;
845         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
846         Base *base;
847         short baseCount = 0;
848         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
849         char str[32];
850         
851         for(base=FIRSTBASE; base; base= base->next) {
852                 if (BASE_SELECTABLE(v3d, base)) {
853                         baseList[baseCount] = NULL;
854                         
855                         /* two selection methods, the CTRL select uses max dist of 15 */
856                         if(buffer) {
857                                 int a;
858                                 for(a=0; a<hits; a++) {
859                                         /* index was converted */
860                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
861                                 }
862                         }
863                         else {
864                                 int temp, dist=15;
865                                 
866                                 project_short(vc->ar, base->object->obmat[3], &base->sx);
867                                 
868                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
869                                 if(temp<dist ) baseList[baseCount] = base;
870                         }
871                         
872                         if(baseList[baseCount]) {
873                                 if (baseCount < SEL_MENU_SIZE) {
874                                         baseList[baseCount] = base;
875                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
876                                                         strcat(menuText, str);
877                                                         baseCount++;
878                                 }
879                         }
880                 }
881         }
882
883         if(baseCount<=1) return baseList[0];
884         else {
885                 baseCount = -1; // XXX = pupmenu(menuText);
886                 
887                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
888                         return baseList[baseCount-1];
889                 }
890                 else return NULL;
891         }
892 }
893
894 /* we want a select buffer with bones, if there are... */
895 /* so check three selection levels and compare */
896 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
897 {
898         rcti rect;
899         int offs;
900         short a, hits15, hits9=0, hits5=0;
901         short has_bones15=0, has_bones9=0, has_bones5=0;
902         
903         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
904         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
905         if(hits15>0) {
906                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
907                 
908                 offs= 4*hits15;
909                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
910                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
911                 if(hits9>0) {
912                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
913                         
914                         offs+= 4*hits9;
915                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
916                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
917                         if(hits5>0) {
918                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
919                         }
920                 }
921                 
922                 if(has_bones5) {
923                         offs= 4*hits15 + 4*hits9;
924                         memcpy(buffer, buffer+offs, 4*offs);
925                         return hits5;
926                 }
927                 if(has_bones9) {
928                         offs= 4*hits15;
929                         memcpy(buffer, buffer+offs, 4*offs);
930                         return hits9;
931                 }
932                 if(has_bones15) {
933                         return hits15;
934                 }
935                 
936                 if(hits5>0) {
937                         offs= 4*hits15 + 4*hits9;
938                         memcpy(buffer, buffer+offs, 4*offs);
939                         return hits5;
940                 }
941                 if(hits9>0) {
942                         offs= 4*hits15;
943                         memcpy(buffer, buffer+offs, 4*offs);
944                         return hits9;
945                 }
946                 return hits15;
947         }
948         
949         return 0;
950 }
951
952
953 /* mval is region coords */
954 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
955 {
956         ViewContext vc;
957         ARegion *ar= CTX_wm_region(C);
958         View3D *v3d= CTX_wm_view3d(C);
959         Scene *scene= CTX_data_scene(C);
960         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
961         unsigned int buffer[4*MAXPICKBUF];
962         int temp, a, dist=100;
963         short hits;
964         
965         /* setup view context for argument to callbacks */
966         view3d_set_viewcontext(C, &vc);
967         
968         /* always start list from basact in wire mode */
969         startbase=  FIRSTBASE;
970         if(BASACT && BASACT->next) startbase= BASACT->next;
971         
972         /* This block uses the control key to make the object selected by its center point rather then its contents */
973         /* XXX later on, in editmode do not activate */
974         if(vc.obedit==NULL && obcenter) {
975                 
976                 /* note; shift+alt goes to group-flush-selecting */
977                 /* XXX solve */
978                 if(0) 
979                         basact= mouse_select_menu(&vc, NULL, 0, mval);
980                 else {
981                         base= startbase;
982                         while(base) {
983                                 if (BASE_SELECTABLE(v3d, base)) {
984                                         project_short(ar, base->object->obmat[3], &base->sx);
985                                         
986                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
987                                         if(base==BASACT) temp+=10;
988                                         if(temp<dist ) {
989                                                 
990                                                 dist= temp;
991                                                 basact= base;
992                                         }
993                                 }
994                                 base= base->next;
995                                 
996                                 if(base==0) base= FIRSTBASE;
997                                 if(base==startbase) break;
998                         }
999                 }
1000         }
1001         else {
1002                 /* if objects have posemode set, the bones are in the same selection buffer */
1003                 
1004                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1005                 
1006                 if(hits>0) {
1007                         int has_bones= 0;
1008                         
1009                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1010
1011                         /* note; shift+alt goes to group-flush-selecting */
1012                         if(has_bones==0 && 0) 
1013                                 basact= mouse_select_menu(&vc, buffer, hits, mval);
1014                         else {
1015                                 static short lastmval[2]={-100, -100};
1016                                 int donearest= 0;
1017                                 
1018                                 /* define if we use solid nearest select or not */
1019                                 if(v3d->drawtype>OB_WIRE) {
1020                                         donearest= 1;
1021                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1022                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1023                                                         donearest= 0;
1024                                         }
1025                                 }
1026                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1027                                 
1028                                 if(donearest) {
1029                                         unsigned int min= 0xFFFFFFFF;
1030                                         int selcol= 0, notcol=0;
1031                                         
1032
1033                                         if(has_bones) {
1034                                                 /* we skip non-bone hits */
1035                                                 for(a=0; a<hits; a++) {
1036                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1037                                                                 min= buffer[4*a+1];
1038                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1039                                                         }
1040                                                 }
1041                                         }
1042                                         else {
1043                                                 /* only exclude active object when it is selected... */
1044                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1045                                         
1046                                                 for(a=0; a<hits; a++) {
1047                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1048                                                                 min= buffer[4*a+1];
1049                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1050                                                         }
1051                                                 }
1052                                         }
1053
1054                                         base= FIRSTBASE;
1055                                         while(base) {
1056                                                 if(base->lay & v3d->lay) {
1057                                                         if(base->selcol==selcol) break;
1058                                                 }
1059                                                 base= base->next;
1060                                         }
1061                                         if(base) basact= base;
1062                                 }
1063                                 else {
1064                                         
1065                                         base= startbase;
1066                                         while(base) {
1067                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1068                                                  * with an un-selectable choice */
1069                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1070                                                         base=base->next;
1071                                                         if(base==NULL) base= FIRSTBASE;
1072                                                         if(base==startbase) break;
1073                                                 }
1074                                         
1075                                                 if(base->lay & v3d->lay) {
1076                                                         for(a=0; a<hits; a++) {
1077                                                                 if(has_bones) {
1078                                                                         /* skip non-bone objects */
1079                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1080                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1081                                                                                         basact= base;
1082                                                                         }
1083                                                                 }
1084                                                                 else {
1085                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1086                                                                                 basact= base;
1087                                                                 }
1088                                                         }
1089                                                 }
1090                                                 
1091                                                 if(basact) break;
1092                                                 
1093                                                 base= base->next;
1094                                                 if(base==NULL) base= FIRSTBASE;
1095                                                 if(base==startbase) break;
1096                                         }
1097                                 }
1098                         }
1099                         
1100                         if(has_bones && basact) {
1101                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1102                                 
1103                                         /* we make the armature selected: 
1104                                            not-selected active object in posemode won't work well for tools */
1105                                         basact->flag|= SELECT;
1106                                         basact->object->flag= basact->flag;
1107                                         
1108                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1109                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1110                                         
1111                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1112                                         if(G.f & G_WEIGHTPAINT) {
1113                                                 /* prevent activating */
1114                                                 basact= NULL;
1115                                         }
1116
1117                                 }
1118                                 /* prevent bone selecting to pass on to object selecting */
1119                                 if(basact==BASACT)
1120                                         basact= NULL;
1121                         }
1122                 }
1123         }
1124         
1125         /* so, do we have something selected? */
1126         if(basact) {
1127                 
1128                 if(vc.obedit) {
1129                         /* only do select */
1130                         deselectall_except(scene, basact);
1131                         ED_base_object_select(basact, BA_SELECT);
1132                 }
1133                 /* also prevent making it active on mouse selection */
1134                 else if (BASE_SELECTABLE(v3d, basact)) {
1135
1136                         oldbasact= BASACT;
1137                         
1138                         if(!extend) {
1139                                 deselectall_except(scene, basact);
1140                                 ED_base_object_select(basact, BA_SELECT);
1141                         }
1142                         else if(0) {
1143                                 // XXX select_all_from_groups(basact);
1144                         }
1145                         else {
1146                                 if(basact->flag & SELECT) {
1147                                         if(basact==oldbasact)
1148                                                 ED_base_object_select(basact, BA_DESELECT);
1149                                 }
1150                                 else ED_base_object_select(basact, BA_SELECT);
1151                         }
1152
1153                         if(oldbasact != basact) {
1154                                 ED_base_object_activate(C, basact); /* adds notifier */
1155                         }
1156
1157                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1158                 }
1159         }
1160 }
1161
1162 /* ********************  border and circle ************************************** */
1163
1164
1165 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1166 {
1167         int radsq= rad*rad;
1168         float v1[2], v2[2], v3[2];
1169         
1170         /* check points in circle itself */
1171         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1172         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1173         
1174         /* pointdistline */
1175         v3[0]= centx;
1176         v3[1]= centy;
1177         v1[0]= x1;
1178         v1[1]= y1;
1179         v2[0]= x2;
1180         v2[1]= y2;
1181         
1182         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1183         
1184         return 0;
1185 }
1186
1187 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1188 {
1189         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1190
1191         if (BLI_in_rcti(data->rect, x, y)) {
1192                 if (bp) {
1193                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1194                 } else {
1195                         if (G.f & G_HIDDENHANDLES) {
1196                                 /* can only be beztindex==0 here since handles are hidden */
1197                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1198                         } else {
1199                                 if (beztindex==0) {
1200                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1201                                 } else if (beztindex==1) {
1202                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1203                                 } else {
1204                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1205                                 }
1206                         }
1207                 }
1208         }
1209 }
1210 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1211 {
1212         struct { ViewContext vc; rcti *rect; int select; } data;
1213         
1214         data.vc= *vc;
1215         data.rect = rect;
1216         data.select = select;
1217
1218         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1219 }
1220
1221 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1222 {
1223         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1224
1225         if (BLI_in_rcti(data->rect, x, y)) {
1226                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1227         }
1228 }
1229 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1230 {
1231         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1232
1233         data.vc= *vc;
1234         data.rect = rect;
1235         data.select = select;
1236
1237         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1238 }
1239
1240 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1241 {
1242         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1243
1244         if (BLI_in_rcti(data->rect, x, y)) {
1245                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1246         }
1247 }
1248 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1249 {
1250         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1251
1252         if(EM_check_backbuf(em_solidoffs+index)) {
1253                 if (data->pass==0) {
1254                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1255                                 EM_select_edge(eed, data->select);
1256                                 data->done = 1;
1257                         }
1258                 } else {
1259                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1260                                 EM_select_edge(eed, data->select);
1261                         }
1262                 }
1263         }
1264 }
1265 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1266 {
1267         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1268
1269         if (BLI_in_rcti(data->rect, x, y)) {
1270                 EM_select_face_fgon(data->vc.em, efa, data->select);
1271         }
1272 }
1273 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1274 {
1275         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1276         ToolSettings *ts= vc->scene->toolsettings;
1277         int bbsel;
1278         
1279         data.vc= *vc;
1280         data.rect = rect;
1281         data.select = select;
1282         data.pass = 0;
1283         data.done = 0;
1284
1285         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1286
1287         if(ts->selectmode & SCE_SELECT_VERTEX) {
1288                 if (bbsel) {
1289                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1290                 } else {
1291                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1292                 }
1293         }
1294         if(ts->selectmode & SCE_SELECT_EDGE) {
1295                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1296
1297                 data.pass = 0;
1298                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1299
1300                 if (data.done==0) {
1301                         data.pass = 1;
1302                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1303                 }
1304         }
1305         
1306         if(ts->selectmode & SCE_SELECT_FACE) {
1307                 if(bbsel) {
1308                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1309                 } else {
1310                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1311                 }
1312         }
1313         
1314         EM_free_backbuf();
1315                 
1316         EM_selectmode_flush(vc->em);
1317 }
1318
1319 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1320 {
1321         ViewContext vc;
1322         Scene *scene= CTX_data_scene(C);
1323         ScrArea *sa= CTX_wm_area(C);
1324         View3D *v3d= sa->spacedata.first;
1325         Object *obedit= CTX_data_edit_object(C);
1326         rcti rect;
1327         Base *base;
1328         MetaElem *ml;
1329         unsigned int buffer[4*MAXPICKBUF];
1330         int a, index;
1331         short hits, val;
1332
1333         view3d_operator_needs_opengl(C);
1334         
1335         /* setup view context for argument to callbacks */
1336         view3d_set_viewcontext(C, &vc);
1337         
1338         val= RNA_int_get(op->ptr, "event_type");
1339         rect.xmin= RNA_int_get(op->ptr, "xmin");
1340         rect.ymin= RNA_int_get(op->ptr, "ymin");
1341         rect.xmax= RNA_int_get(op->ptr, "xmax");
1342         rect.ymax= RNA_int_get(op->ptr, "ymax");
1343         
1344         if(obedit==NULL && (FACESEL_PAINT_TEST)) {
1345 // XXX          face_borderselect();
1346                 return OPERATOR_FINISHED;
1347         }
1348         else if(obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1349                 return PE_border_select(C, &rect, (val==LEFTMOUSE));
1350         }
1351         
1352         if(obedit) {
1353                 if(obedit->type==OB_MESH) {
1354                         Mesh *me= obedit->data;
1355                         vc.em= me->edit_mesh;
1356                         do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1357 //                      if (EM_texFaceCheck())
1358                         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1359                         
1360                 }
1361                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1362                         do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1363                 }
1364                 else if(obedit->type==OB_MBALL) {
1365                         MetaBall *mb = (MetaBall*)obedit->data;
1366                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1367                         
1368                         ml= mb->editelems->first;
1369                         
1370                         while(ml) {
1371                                 for(a=0; a<hits; a++) {
1372                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1373                                                 ml->flag |= MB_SCALE_RAD;
1374                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1375                                                 else ml->flag &= ~SELECT;
1376                                                 break;
1377                                         }
1378                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1379                                                 ml->flag &= ~MB_SCALE_RAD;
1380                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1381                                                 else ml->flag &= ~SELECT;
1382                                                 break;
1383                                         }
1384                                 }
1385                                 ml= ml->next;
1386                         }
1387                 }
1388                 else if(obedit->type==OB_ARMATURE) {
1389                         bArmature *arm= obedit->data;
1390                         EditBone *ebone;
1391                         
1392                         /* clear flag we use to detect point was affected */
1393                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1394                                 ebone->flag &= ~BONE_DONE;
1395                         
1396                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1397                         
1398                         /* first we only check points inside the border */
1399                         for (a=0; a<hits; a++){
1400                                 index = buffer[(4*a)+3];
1401                                 if (index!=-1) {
1402                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1403                                         if (index & BONESEL_TIP) {
1404                                                 ebone->flag |= BONE_DONE;
1405                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1406                                                 else ebone->flag &= ~BONE_TIPSEL;
1407                                         }
1408                                         
1409                                         if (index & BONESEL_ROOT) {
1410                                                 ebone->flag |= BONE_DONE;
1411                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1412                                                 else ebone->flag &= ~BONE_ROOTSEL;
1413                                         }
1414                                 }
1415                         }
1416                         
1417                         /* now we have to flush tag from parents... */
1418                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1419                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1420                                         if(ebone->parent->flag & BONE_DONE)
1421                                                 ebone->flag |= BONE_DONE;
1422                                 }
1423                         }
1424                         
1425                         /* only select/deselect entire bones when no points where in the rect */
1426                         for (a=0; a<hits; a++){
1427                                 index = buffer[(4*a)+3];
1428                                 if (index!=-1) {
1429                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1430                                         if (index & BONESEL_BONE) {
1431                                                 if(!(ebone->flag & BONE_DONE)) {
1432                                                         if (val==LEFTMOUSE)
1433                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1434                                                         else
1435                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1436                                                 }
1437                                         }
1438                                 }
1439                         }
1440                         
1441                         ED_armature_sync_selection(arm->edbo);
1442                 }
1443                 else if(obedit->type==OB_LATTICE) {
1444                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1445                 }
1446         }
1447         else {  /* no editmode, unified for bones and objects */
1448                 Bone *bone;
1449                 Object *ob= OBACT;
1450                 unsigned int *vbuffer=NULL; /* selection buffer */
1451                 unsigned int *col;                      /* color in buffer      */
1452                 short selecting = 0;
1453                 int bone_only;
1454                 int totobj= MAXPICKBUF; // XXX solve later
1455                 
1456                 if((ob) && (ob->flag & OB_POSEMODE))
1457                         bone_only= 1;
1458                 else
1459                         bone_only= 0;
1460                 
1461                 if (val==LEFTMOUSE)
1462                         selecting = 1;
1463                 
1464                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1465                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1466                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1467                 /*
1468                 LOGIC NOTES (theeth):
1469                 The buffer and ListBase have the same relative order, which makes the selection
1470                 very simple. Loop through both data sets at the same time, if the color
1471                 is the same as the object, we have a hit and can move to the next color
1472                 and object pair, if not, just move to the next object,
1473                 keeping the same color until we have a hit.
1474
1475                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1476                 does it incorrectly.
1477                 */
1478
1479                 if (hits>0) { /* no need to loop if there's no hit */
1480                         base= FIRSTBASE;
1481                         col = vbuffer + 3;
1482                         
1483                         while(base && hits) {
1484                                 Base *next = base->next;
1485                                 if(base->lay & v3d->lay) {
1486                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1487                                                 
1488                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1489                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1490                                                         if(bone) {
1491                                                                 if(selecting) {
1492                                                                         bone->flag |= BONE_SELECTED;
1493 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1494                                                                 }
1495                                                                 else {
1496                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1497 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1498                                                                 }
1499                                                         }
1500                                                 }
1501                                                 else if(!bone_only) {
1502                                                         if (selecting)
1503                                                                 ED_base_object_select(base, BA_SELECT);
1504                                                         else
1505                                                                 ED_base_object_select(base, BA_DESELECT);
1506                                                 }
1507
1508                                                 col+=4; /* next color */
1509                                                 hits--;
1510                                                 if(hits==0) break;
1511                                         }
1512                                 }
1513                                 
1514                                 base= next;
1515                         }
1516
1517                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1518
1519                 }
1520                 MEM_freeN(vbuffer);
1521         }
1522         return OPERATOR_FINISHED;
1523
1524
1525
1526 /* *****************Selection Operators******************* */
1527
1528 /* ****** Border Select ****** */
1529 void VIEW3D_OT_select_border(wmOperatorType *ot)
1530 {
1531         /* identifiers */
1532         ot->name= "Border Select";
1533         ot->idname= "VIEW3D_OT_select_border";
1534         
1535         /* api callbacks */
1536         ot->invoke= WM_border_select_invoke;
1537         ot->exec= view3d_borderselect_exec;
1538         ot->modal= WM_border_select_modal;
1539         
1540         ot->poll= ED_operator_view3d_active;
1541         
1542         /* flags */
1543         ot->flag= OPTYPE_UNDO;
1544         
1545         /* rna */
1546         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1547         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1548         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1549         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1550         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1551
1552         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
1553 }
1554
1555 /* ****** Mouse Select ****** */
1556
1557
1558 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1559 {
1560         Object *obedit= CTX_data_edit_object(C);
1561         short extend= RNA_boolean_get(op->ptr, "extend");
1562
1563         view3d_operator_needs_opengl(C);
1564         
1565         if(obedit) {
1566                 if(obedit->type==OB_MESH)
1567                         mouse_mesh(C, event->mval, extend);
1568                 else if(obedit->type==OB_ARMATURE)
1569                         mouse_armature(C, event->mval, extend);
1570                 else if(obedit->type==OB_LATTICE)
1571                         mouse_lattice(C, event->mval, extend);
1572                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1573                         mouse_nurb(C, event->mval, extend);
1574                 else if(obedit->type==OB_MBALL)
1575                         mouse_mball(C, event->mval, extend);
1576                         
1577         }
1578         else if(G.f & G_PARTICLEEDIT)
1579                 PE_mouse_particles(C, event->mval, extend);
1580         else 
1581                 mouse_select(C, event->mval, extend, 0);
1582
1583         /* allowing tweaks */
1584         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1585 }
1586
1587 void VIEW3D_OT_select(wmOperatorType *ot)
1588 {
1589         /* identifiers */
1590         ot->name= "Activate/Select";
1591         ot->idname= "VIEW3D_OT_select";
1592         
1593         /* api callbacks */
1594         ot->invoke= view3d_select_invoke;
1595         ot->poll= ED_operator_view3d_active;
1596         
1597         /* flags */
1598         ot->flag= OPTYPE_UNDO;
1599         
1600         /* properties */
1601         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
1602 }
1603
1604
1605 /* ****** Drag & Drop ****** */
1606
1607 static int view3d_drag_invoke(bContext *C, wmOperator *op, wmEvent *event)
1608 {
1609         wmWindow *win= CTX_wm_window(C);
1610         Object *ob= CTX_data_active_object(C);
1611         PointerRNA ptr;
1612
1613         RNA_pointer_create(NULL, &RNA_Object, ob, &ptr);
1614
1615         return OPERATOR_RUNNING_MODAL;
1616 }
1617
1618 static int view3d_drag_modal(bContext *C, wmOperator *op, wmEvent *event)
1619 {
1620         switch(event->type) {
1621                 case MOUSEDRAG:
1622
1623                         break;
1624                 case MOUSEDROP:
1625                         return OPERATOR_FINISHED;
1626                 case ESCKEY:
1627                         return OPERATOR_CANCELLED;
1628         }
1629
1630         return OPERATOR_RUNNING_MODAL;
1631 }
1632
1633 static int view3d_drag_exec(bContext *C, wmOperator *op)
1634 {
1635         return OPERATOR_FINISHED;
1636 }
1637
1638 void VIEW3D_OT_drag(wmOperatorType *ot)
1639 {
1640         /* identifiers */
1641         ot->name= "Drag";
1642         ot->idname= "VIEW3D_OT_drag";
1643         
1644         /* api callbacks */
1645         ot->invoke= view3d_drag_invoke;
1646         ot->modal= view3d_drag_modal;
1647         ot->exec= view3d_drag_exec;
1648         ot->poll= ED_operator_view3d_active;
1649         
1650         /* flags */
1651         /* ot->flag= OPTYPE_UNDO; */
1652 }
1653
1654
1655 /* -------------------- circle select --------------------------------------------- */
1656
1657 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1658 {
1659         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1660         int mx = x - data->mval[0], my = y - data->mval[1];
1661         float r = sqrt(mx*mx + my*my);
1662
1663         if (r<=data->radius) {
1664                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1665         }
1666 }
1667 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1668 {
1669         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1670
1671         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1672                 EM_select_edge(eed, data->select);
1673         }
1674 }
1675 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1676 {
1677         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1678         int mx = x - data->mval[0], my = y - data->mval[1];
1679         float r = sqrt(mx*mx + my*my);
1680         
1681         if (r<=data->radius) {
1682                 EM_select_face_fgon(data->vc->em, efa, data->select);
1683         }
1684 }
1685
1686 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1687 {
1688         ToolSettings *ts= vc->scene->toolsettings;
1689         int bbsel;
1690         
1691         if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1692                 Object *ob= vc->obact;
1693                 Mesh *me = ob?ob->data:NULL;
1694
1695                 if (me) {
1696                         em_vertoffs= me->totface+1;     /* max index array */
1697
1698                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1699                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1700                         EM_free_backbuf();
1701
1702 // XXX                  object_tface_flags_changed(OBACT, 0);
1703                 }
1704         }
1705         else {
1706                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1707                 
1708                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1709                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1710
1711                 data.select = selecting;
1712                 data.mval[0] = mval[0];
1713                 data.mval[1] = mval[1];
1714                 data.radius = rad;
1715
1716                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1717                         if(bbsel) {
1718                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1719                         } else {
1720                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1721                         }
1722                 }
1723
1724                 if(ts->selectmode & SCE_SELECT_EDGE) {
1725                         if (bbsel) {
1726                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1727                         } else {
1728                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1729                         }
1730                 }
1731                 
1732                 if(ts->selectmode & SCE_SELECT_FACE) {
1733                         if(bbsel) {
1734                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1735                         } else {
1736                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1737                         }
1738                 }
1739
1740                 EM_free_backbuf();
1741                 EM_selectmode_flush(vc->em);
1742         }
1743 }
1744
1745
1746 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1747 {
1748         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1749         int mx = x - data->mval[0], my = y - data->mval[1];
1750         float r = sqrt(mx*mx + my*my);
1751
1752         if (r<=data->radius) {
1753                 if (bp) {
1754                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1755                 } else {
1756                         if (beztindex==0) {
1757                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1758                         } else if (beztindex==1) {
1759                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1760                         } else {
1761                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1762                         }
1763                 }
1764         }
1765 }
1766 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1767 {
1768         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1769
1770         /* set vc-> edit data */
1771         
1772         data.select = selecting;
1773         data.mval[0] = mval[0];
1774         data.mval[1] = mval[1];
1775         data.radius = rad;
1776
1777         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1778 }
1779
1780
1781 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1782 {
1783         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1784         int mx = x - data->mval[0], my = y - data->mval[1];
1785         float r = sqrt(mx*mx + my*my);
1786
1787         if (r<=data->radius) {
1788                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1789         }
1790 }
1791 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1792 {
1793         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1794
1795         /* set vc-> edit data */
1796         
1797         data.select = selecting;
1798         data.mval[0] = mval[0];
1799         data.mval[1] = mval[1];
1800         data.radius = rad;
1801
1802         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1803 }
1804
1805 /** Callbacks for circle selection in Editmode */
1806
1807 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1808 {
1809         switch(vc->obedit->type) {              
1810         case OB_MESH:
1811                 mesh_circle_select(vc, selecting, mval, rad);
1812                 break;
1813         case OB_CURVE:
1814         case OB_SURF:
1815                 nurbscurve_circle_select(vc, selecting, mval, rad);
1816                 break;
1817         case OB_LATTICE:
1818                 lattice_circle_select(vc, selecting, mval, rad);
1819                 break;
1820         default:
1821                 return;
1822         }
1823 }
1824
1825 /* not a real operator, only for circle test */
1826 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1827 {
1828         ScrArea *sa= CTX_wm_area(C);
1829         ARegion *ar= CTX_wm_region(C);
1830         Scene *scene= CTX_data_scene(C);
1831         View3D *v3d= sa->spacedata.first;
1832         int x= RNA_int_get(op->ptr, "x");
1833         int y= RNA_int_get(op->ptr, "y");
1834         int radius= RNA_int_get(op->ptr, "radius");
1835         
1836         if(CTX_data_edit_object(C) || (G.f & G_PARTICLEEDIT)) {
1837                 ViewContext vc;
1838                 short mval[2], selecting;
1839                 
1840                 view3d_operator_needs_opengl(C);
1841                 
1842                 view3d_set_viewcontext(C, &vc);
1843                 mval[0]= x;
1844                 mval[1]= y;
1845                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1846
1847                 if(CTX_data_edit_object(C))
1848                         obedit_circle_select(&vc, selecting, mval, (float)radius);
1849                 else
1850                         return PE_circle_select(C, selecting, mval, (float)radius);
1851         }
1852         else {
1853                 Base *base;
1854                 
1855                 for(base= FIRSTBASE; base; base= base->next) {
1856                         if(base->lay & v3d->lay) {
1857                                 project_short(ar, base->object->obmat[3], &base->sx);
1858                                 if(base->sx!=IS_CLIPPED) {
1859                                         int dx= base->sx-x;
1860                                         int dy= base->sy-y;
1861                                         if( dx*dx + dy*dy < radius*radius)
1862                                                 ED_base_object_select(base, BA_SELECT);
1863                                 }
1864                         }
1865                 }
1866                 
1867                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1868         }
1869         
1870         return OPERATOR_FINISHED;
1871 }
1872
1873 void VIEW3D_OT_select_circle(wmOperatorType *ot)
1874 {
1875         ot->name= "Circle Select";
1876         ot->idname= "VIEW3D_OT_select_circle";
1877         
1878         ot->invoke= WM_gesture_circle_invoke;
1879         ot->modal= WM_gesture_circle_modal;
1880         ot->exec= view3d_circle_select_exec;
1881         ot->poll= ED_operator_view3d_active;
1882         
1883         /* flags */
1884         ot->flag= OPTYPE_UNDO;
1885         
1886         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1887         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1888         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1889         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1890 }