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