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