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