added back face mask mouse selection and made shift+k fill weight paint and vertex...
[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         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
463         
464         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
465
466         if(ts->selectmode & SCE_SELECT_VERTEX) {
467                 if (bbsel) {
468                         EM_backbuf_checkAndSelectVerts(vc->em, select);
469                 } else {
470                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
471                 }
472         }
473         if(ts->selectmode & SCE_SELECT_EDGE) {
474                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
475
476                 data.pass = 0;
477                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
478
479                 if (data.done==0) {
480                         data.pass = 1;
481                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
482                 }
483         }
484         
485         if(ts->selectmode & SCE_SELECT_FACE) {
486                 if (bbsel) {
487                         EM_backbuf_checkAndSelectFaces(vc->em, select);
488                 } else {
489                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
490                 }
491         }
492         
493         EM_free_backbuf();
494         EM_selectmode_flush(vc->em);    
495 }
496
497 #if 0
498 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
499 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
500 {
501         EditFace *efa;
502         MTFace *tf;
503         int screenUV[2], nverts, i, ok = 1;
504         rcti rect;
505         
506         lasso_select_boundbox(&rect, mcords, moves);
507         
508         if (draw_uvs_face_check()) { /* Face Center Sel */
509                 float cent[2];
510                 ok = 0;
511                 for (efa= em->faces.first; efa; efa= efa->next) {
512                         /* assume not touched */
513                         efa->tmp.l = 0;
514                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
515                         if ((select) != (simaFaceSel_Check(efa, tf))) {
516                                 uv_center(tf->uv, cent, (void *)efa->v4);
517                                 uvco_to_areaco_noclip(cent, screenUV);
518                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
519                                         efa->tmp.l = ok = 1;
520                                 }
521                         }
522                 }
523                 /* (de)selects all tagged faces and deals with sticky modes */
524                 if (ok)
525                         uvface_setsel__internal(select);
526                 
527         } else { /* Vert Sel*/
528                 for (efa= em->faces.first; efa; efa= efa->next) {
529                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
530                         if (simaFaceDraw_Check(efa, tf)) {              
531                                 nverts= efa->v4? 4: 3;
532                                 for(i=0; i<nverts; i++) {
533                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
534                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
535                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
536                                                         if (select) {
537                                                                 simaUVSel_Set(efa, tf, i);
538                                                         } else {
539                                                                 simaUVSel_UnSet(efa, tf, i);
540                                                         }
541                                                 }
542                                         }
543                                 }
544                         }
545                 }
546         }
547         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
548                 if (select) EM_select_flush(vc->em);
549                 else            EM_deselect_flush(vc->em);
550         }
551 }
552 #endif
553
554 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
555 {
556         struct { ViewContext vc; short (*mcords)[2]; short moves; short select; } *data = userData;
557         
558         if (lasso_inside(data->mcords, data->moves, x, y)) {
559                 if (bp) {
560                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
561                 } else {
562                         Curve *cu= data->vc.obedit->data;
563                         
564                         if (cu->drawflag & CU_HIDE_HANDLES) {
565                                 /* can only be beztindex==0 here since handles are hidden */
566                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
567                         } else {
568                                 if (beztindex==0) {
569                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
570                                 } else if (beztindex==1) {
571                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
572                                 } else {
573                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
574                                 }
575                         }
576                 }
577         }
578 }
579
580 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
581 {
582         struct { ViewContext vc; short (*mcords)[2]; short moves; short select; } data;
583
584         /* set vc->editnurb */
585         data.vc = *vc;
586         data.mcords = mcords;
587         data.moves = moves;
588         data.select = select;
589
590         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
591         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
592 }
593
594 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
595 {
596         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
597
598         if (lasso_inside(data->mcords, data->moves, x, y)) {
599                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
600         }
601 }
602 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
603 {
604         struct { short (*mcords)[2]; short moves; short select; } data;
605
606         /* set editdata in vc */
607         data.mcords = mcords;
608         data.moves = moves;
609         data.select = select;
610
611         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
612         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
613 }
614
615 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
616 {
617         bArmature *arm= vc->obedit->data;
618         EditBone *ebone;
619         float vec[3];
620         short sco1[2], sco2[2], didpoint;
621         
622         /* set editdata in vc */
623         
624         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
625
626                 VECCOPY(vec, ebone->head);
627                 Mat4MulVecfl(vc->obedit->obmat, vec);
628                 project_short(vc->ar, vec, sco1);
629                 VECCOPY(vec, ebone->tail);
630                 Mat4MulVecfl(vc->obedit->obmat, vec);
631                 project_short(vc->ar, vec, sco2);
632                 
633                 didpoint= 0;
634                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
635                         if(select) ebone->flag |= BONE_ROOTSEL;
636                         else ebone->flag &= ~BONE_ROOTSEL;
637                         didpoint= 1;
638                 }
639                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
640                    if(select) ebone->flag |= BONE_TIPSEL;
641                    else ebone->flag &= ~BONE_TIPSEL;
642                    didpoint= 1;
643                 }
644                 /* if one of points selected, we skip the bone itself */
645                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
646                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
647                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
648                 }
649         }
650 }
651
652 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
653 {
654         Object *ob= vc->obact;
655         Mesh *me= ob?ob->data:NULL;
656         rcti rect;
657         
658         if(me==NULL || me->mtface==NULL) return;
659         if(me->totface==0) return;
660         
661         em_vertoffs= me->totface+1;     /* max index array */
662         
663         lasso_select_boundbox(&rect, mcords, moves);
664         EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
665         
666         EM_backbuf_checkAndSelectTFaces(me, select);
667         
668         EM_free_backbuf();
669         
670 // XXX  object_tface_flags_changed(ob, 0);
671 }
672
673 #if 0
674 static void do_lasso_select_node(short mcords[][2], short moves, short select)
675 {
676         SpaceNode *snode = sa->spacedata.first;
677         
678         bNode *node;
679         rcti rect;
680         short node_cent[2];
681         float node_centf[2];
682         
683         lasso_select_boundbox(&rect, mcords, moves);
684         
685         /* store selection in temp test flag */
686         for(node= snode->edittree->nodes.first; node; node= node->next) {
687                 
688                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
689                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
690                 
691                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
692                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
693                         if (select) {
694                                 node->flag |= SELECT;
695                         } else {
696                                 node->flag &= ~SELECT;
697                         }
698                 }
699         }
700         BIF_undo_push("Lasso select nodes");
701 }
702 #endif
703
704 void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short moves, short select)
705 {
706         Object *ob = CTX_data_active_object(C);
707
708         if(vc->obedit==NULL) {
709                 if(paint_facesel_test(ob))
710                         do_lasso_select_facemode(vc, mcords, moves, select);
711                 else if(ob && ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))
712                         ;
713                 else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT)
714                         PE_lasso_select(C, mcords, moves, select);
715                 else  
716                         do_lasso_select_objects(vc, mcords, moves, select);
717         }
718         else if(vc->obedit->type==OB_MESH) {
719                 do_lasso_select_mesh(vc, mcords, moves, select);
720         } else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF) 
721                 do_lasso_select_curve(vc, mcords, moves, select);
722         else if(vc->obedit->type==OB_LATTICE) 
723                 do_lasso_select_lattice(vc, mcords, moves, select);
724         else if(vc->obedit->type==OB_ARMATURE)
725                 do_lasso_select_armature(vc, mcords, moves, select);
726
727         BIF_undo_push("Lasso select");
728         
729 }
730
731
732 /* lasso operator gives properties, but since old code works
733    with short array we convert */
734 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
735 {
736         ViewContext vc;
737         int select, i= 0;
738         short mcords[1024][2];
739
740         RNA_BEGIN(op->ptr, itemptr, "path") {
741                 float loc[2];
742                 
743                 RNA_float_get_array(&itemptr, "loc", loc);
744                 mcords[i][0]= (short)loc[0];
745                 mcords[i][1]= (short)loc[1];
746                 i++;
747                 if(i>=1024) break;
748         }
749         RNA_END;
750         
751         if(i>1) {
752                 view3d_operator_needs_opengl(C);
753                 
754                 /* setup view context for argument to callbacks */
755                 view3d_set_viewcontext(C, &vc);
756                 
757                 select= !RNA_boolean_get(op->ptr, "deselect");
758                 view3d_lasso_select(C, &vc, mcords, i, select);
759                 
760                 return OPERATOR_FINISHED;
761         }
762         return OPERATOR_PASS_THROUGH;
763 }
764
765 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
766 {
767         ot->name= "Lasso Select";
768         ot->description= "Select items using lasso selection.";
769         ot->idname= "VIEW3D_OT_select_lasso";
770         
771         ot->invoke= WM_gesture_lasso_invoke;
772         ot->modal= WM_gesture_lasso_modal;
773         ot->exec= view3d_lasso_select_exec;
774         ot->poll= WM_operator_winactive;
775         
776         /* flags */
777         ot->flag= OPTYPE_UNDO;
778         
779         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
780         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items.");
781 }
782
783
784 /* ************************************************* */
785
786 #if 0
787 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
788 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
789 {
790         Base *base;
791         unsigned int *bufmin,*bufmax;
792         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
793         unsigned int retval=0;
794         
795         base= LASTBASE;
796         if(base==0) return 0;
797         maxob= base->selcol;
798
799         aantal= (size-1)/2;
800         rc= 0;
801
802         dirvec[0][0]= 1;
803         dirvec[0][1]= 0;
804         dirvec[1][0]= 0;
805         dirvec[1][1]= -size;
806         dirvec[2][0]= -1;
807         dirvec[2][1]= 0;
808         dirvec[3][0]= 0;
809         dirvec[3][1]= size;
810
811         bufmin= buf;
812         bufmax= buf+ size*size;
813         buf+= aantal*size+ aantal;
814
815         for(tel=1;tel<=size;tel++) {
816
817                 for(a=0;a<2;a++) {
818                         for(b=0;b<tel;b++) {
819
820                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
821                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
822                                 
823                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
824
825                                 if(buf<bufmin || buf>=bufmax) return retval;
826                         }
827                         rc++;
828                         rc &= 3;
829                 }
830         }
831         return retval;
832 }
833 #endif
834
835 /* ************************** mouse select ************************* */
836
837
838 /* The max number of menu items in an object select menu */
839 #define SEL_MENU_SIZE   22
840
841 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
842 {
843         Base *base;
844         
845         for(base= FIRSTBASE; base; base= base->next) {
846                 if (base->flag & SELECT) {
847                         if(b!=base) {
848                                 ED_base_object_select(base, BA_DESELECT);
849                         }
850                 }
851         }
852 }
853
854 static Base *mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, short *mval, short extend)
855 {
856         short baseCount = 0;
857         short ok;
858         LinkNode *linklist= NULL;
859         
860         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
861                 ok= FALSE;
862
863                 /* two selection methods, the CTRL select uses max dist of 15 */
864                 if(buffer) {
865                         int a;
866                         for(a=0; a<hits; a++) {
867                                 /* index was converted */
868                                 if(base->selcol==buffer[ (4 * a) + 3 ])
869                                         ok= TRUE;
870                         }
871                 }
872                 else {
873                         int temp, dist=15;
874
875                         project_short(vc->ar, base->object->obmat[3], &base->sx);
876                         
877                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
878                         if(temp < dist)
879                                 ok= TRUE;
880                 }
881
882                 if(ok) {
883                         baseCount++;
884                         BLI_linklist_prepend(&linklist, base);
885
886                         if (baseCount==SEL_MENU_SIZE)
887                                 break;
888                 }
889         }
890         CTX_DATA_END;
891
892         if(baseCount)
893
894
895         if(baseCount==0) {
896                 return NULL;
897         }
898         if(baseCount == 1) {
899                 Base *base= (Base *)linklist->link;
900                 BLI_linklist_free(linklist, NULL);
901                 return base;
902         }
903         else {
904                 /* UI */
905                 uiPopupMenu *pup= uiPupMenuBegin(C, "Select Object", 0);
906                 uiLayout *layout= uiPupMenuLayout(pup);
907                 uiLayout *split= uiLayoutSplit(layout, 0);
908                 uiLayout *column= uiLayoutColumn(split, 0);
909                 LinkNode *node;
910
911                 node= linklist;
912                 while(node) {
913                         Base *base=node->link;
914                         Object *ob= base->object;
915                         char *name= ob->id.name+2;
916                         /* annoying!, since we need to set 2 props cant use this. */
917                         /* uiItemStringO(column, name, 0, "OBJECT_OT_select_name", "name", name); */
918
919                         {
920                                 PointerRNA ptr;
921
922                                 WM_operator_properties_create(&ptr, "OBJECT_OT_select_name");
923                                 RNA_string_set(&ptr, "name", name);
924                                 RNA_boolean_set(&ptr, "extend", extend);
925                                 uiItemFullO(column, name, uiIconFromID((ID *)ob), "OBJECT_OT_select_name", ptr.data, WM_OP_EXEC_DEFAULT, 0);
926                         }
927
928                         node= node->next;
929                 }
930
931                 uiPupMenuEnd(C, pup);
932
933                 BLI_linklist_free(linklist, NULL);
934                 return NULL;
935         }
936 }
937
938 /* we want a select buffer with bones, if there are... */
939 /* so check three selection levels and compare */
940 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
941 {
942         rcti rect;
943         int offs;
944         short a, hits15, hits9=0, hits5=0;
945         short has_bones15=0, has_bones9=0, has_bones5=0;
946         
947         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
948         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
949         if(hits15>0) {
950                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
951                 
952                 offs= 4*hits15;
953                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
954                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
955                 if(hits9>0) {
956                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
957                         
958                         offs+= 4*hits9;
959                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
960                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
961                         if(hits5>0) {
962                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
963                         }
964                 }
965                 
966                 if(has_bones5) {
967                         offs= 4*hits15 + 4*hits9;
968                         memcpy(buffer, buffer+offs, 4*offs);
969                         return hits5;
970                 }
971                 if(has_bones9) {
972                         offs= 4*hits15;
973                         memcpy(buffer, buffer+offs, 4*offs);
974                         return hits9;
975                 }
976                 if(has_bones15) {
977                         return hits15;
978                 }
979                 
980                 if(hits5>0) {
981                         offs= 4*hits15 + 4*hits9;
982                         memcpy(buffer, buffer+offs, 4*offs);
983                         return hits5;
984                 }
985                 if(hits9>0) {
986                         offs= 4*hits15;
987                         memcpy(buffer, buffer+offs, 4*offs);
988                         return hits9;
989                 }
990                 return hits15;
991         }
992         
993         return 0;
994 }
995
996
997 /* mval is region coords */
998 static void mouse_select(bContext *C, short *mval, short extend, short obcenter, short enumerate)
999 {
1000         ViewContext vc;
1001         ARegion *ar= CTX_wm_region(C);
1002         View3D *v3d= CTX_wm_view3d(C);
1003         Scene *scene= CTX_data_scene(C);
1004         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1005         int temp, a, dist=100;
1006         short hits;
1007         
1008         /* setup view context for argument to callbacks */
1009         view3d_set_viewcontext(C, &vc);
1010         
1011         /* always start list from basact in wire mode */
1012         startbase=  FIRSTBASE;
1013         if(BASACT && BASACT->next) startbase= BASACT->next;
1014         
1015         /* This block uses the control key to make the object selected by its center point rather then its contents */
1016         /* XXX later on, in editmode do not activate */
1017         if(vc.obedit==NULL && obcenter) {
1018                 
1019                 /* note; shift+alt goes to group-flush-selecting */
1020                 if(enumerate) {
1021                         basact= mouse_select_menu(C, &vc, NULL, 0, mval, extend);
1022                 } else {
1023                         base= startbase;
1024                         while(base) {
1025                                 if (BASE_SELECTABLE(v3d, base)) {
1026                                         project_short(ar, base->object->obmat[3], &base->sx);
1027                                         
1028                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1029                                         if(base==BASACT) temp+=10;
1030                                         if(temp<dist ) {
1031                                                 
1032                                                 dist= temp;
1033                                                 basact= base;
1034                                         }
1035                                 }
1036                                 base= base->next;
1037                                 
1038                                 if(base==0) base= FIRSTBASE;
1039                                 if(base==startbase) break;
1040                         }
1041                 }
1042         }
1043         else {
1044                 unsigned int buffer[4*MAXPICKBUF];
1045
1046                 /* if objects have posemode set, the bones are in the same selection buffer */
1047                 
1048                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1049                 
1050                 if(hits>0) {
1051                         int has_bones= 0;
1052                         
1053                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1054
1055                         /* note; shift+alt goes to group-flush-selecting */
1056                         if(has_bones==0 && enumerate) {
1057                                 basact= mouse_select_menu(C, &vc, buffer, hits, mval, extend);
1058                         } else {
1059                                 static short lastmval[2]={-100, -100};
1060                                 int donearest= 0;
1061                                 
1062                                 /* define if we use solid nearest select or not */
1063                                 if(v3d->drawtype>OB_WIRE) {
1064                                         donearest= 1;
1065                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1066                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1067                                                         donearest= 0;
1068                                         }
1069                                 }
1070                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1071                                 
1072                                 if(donearest) {
1073                                         unsigned int min= 0xFFFFFFFF;
1074                                         int selcol= 0, notcol=0;
1075                                         
1076
1077                                         if(has_bones) {
1078                                                 /* we skip non-bone hits */
1079                                                 for(a=0; a<hits; a++) {
1080                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1081                                                                 min= buffer[4*a+1];
1082                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1083                                                         }
1084                                                 }
1085                                         }
1086                                         else {
1087                                                 /* only exclude active object when it is selected... */
1088                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1089                                         
1090                                                 for(a=0; a<hits; a++) {
1091                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1092                                                                 min= buffer[4*a+1];
1093                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1094                                                         }
1095                                                 }
1096                                         }
1097
1098                                         base= FIRSTBASE;
1099                                         while(base) {
1100                                                 if(base->lay & v3d->lay) {
1101                                                         if(base->selcol==selcol) break;
1102                                                 }
1103                                                 base= base->next;
1104                                         }
1105                                         if(base) basact= base;
1106                                 }
1107                                 else {
1108                                         
1109                                         base= startbase;
1110                                         while(base) {
1111                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1112                                                  * with an un-selectable choice */
1113                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1114                                                         base=base->next;
1115                                                         if(base==NULL) base= FIRSTBASE;
1116                                                         if(base==startbase) break;
1117                                                 }
1118                                         
1119                                                 if(base->lay & v3d->lay) {
1120                                                         for(a=0; a<hits; a++) {
1121                                                                 if(has_bones) {
1122                                                                         /* skip non-bone objects */
1123                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1124                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1125                                                                                         basact= base;
1126                                                                         }
1127                                                                 }
1128                                                                 else {
1129                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1130                                                                                 basact= base;
1131                                                                 }
1132                                                         }
1133                                                 }
1134                                                 
1135                                                 if(basact) break;
1136                                                 
1137                                                 base= base->next;
1138                                                 if(base==NULL) base= FIRSTBASE;
1139                                                 if(base==startbase) break;
1140                                         }
1141                                 }
1142                         }
1143                         
1144                         if(has_bones && basact) {
1145                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1146                                 
1147                                         /* we make the armature selected: 
1148                                            not-selected active object in posemode won't work well for tools */
1149                                         basact->flag|= SELECT;
1150                                         basact->object->flag= basact->flag;
1151                                         
1152                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1153                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1154                                         
1155                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1156                                         if(BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) {
1157                                                 /* prevent activating */
1158                                                 basact= NULL;
1159                                         }
1160
1161                                 }
1162                                 /* prevent bone selecting to pass on to object selecting */
1163                                 if(basact==BASACT)
1164                                         basact= NULL;
1165                         }
1166                 }
1167         }
1168         
1169         /* so, do we have something selected? */
1170         if(basact) {
1171                 
1172                 if(vc.obedit) {
1173                         /* only do select */
1174                         deselectall_except(scene, basact);
1175                         ED_base_object_select(basact, BA_SELECT);
1176                 }
1177                 /* also prevent making it active on mouse selection */
1178                 else if (BASE_SELECTABLE(v3d, basact)) {
1179
1180                         oldbasact= BASACT;
1181                         
1182                         if(!extend) {
1183                                 deselectall_except(scene, basact);
1184                                 ED_base_object_select(basact, BA_SELECT);
1185                         }
1186                         else if(0) {
1187                                 // XXX select_all_from_groups(basact);
1188                         }
1189                         else {
1190                                 if(basact->flag & SELECT) {
1191                                         if(basact==oldbasact)
1192                                                 ED_base_object_select(basact, BA_DESELECT);
1193                                 }
1194                                 else ED_base_object_select(basact, BA_SELECT);
1195                         }
1196
1197                         if(oldbasact != basact) {
1198                                 ED_base_object_activate(C, basact); /* adds notifier */
1199                         }
1200
1201                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1202                 }
1203         }
1204 }
1205
1206 /* ********************  border and circle ************************************** */
1207
1208
1209 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1210 {
1211         int radsq= rad*rad;
1212         float v1[2], v2[2], v3[2];
1213         
1214         /* check points in circle itself */
1215         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1216         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1217         
1218         /* pointdistline */
1219         v3[0]= centx;
1220         v3[1]= centy;
1221         v1[0]= x1;
1222         v1[1]= y1;
1223         v2[0]= x2;
1224         v2[1]= y2;
1225         
1226         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1227         
1228         return 0;
1229 }
1230
1231 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1232 {
1233         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1234
1235         if (BLI_in_rcti(data->rect, x, y)) {
1236                 if (bp) {
1237                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1238                 } else {
1239                         Curve *cu= data->vc.obedit->data;
1240                         
1241                         if (cu->drawflag & CU_HIDE_HANDLES) {
1242                                 /* can only be beztindex==0 here since handles are hidden */
1243                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1244                         } else {
1245                                 if (beztindex==0) {
1246                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1247                                 } else if (beztindex==1) {
1248                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1249                                 } else {
1250                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1251                                 }
1252                         }
1253                 }
1254         }
1255 }
1256 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1257 {
1258         struct { ViewContext vc; rcti *rect; int select; } data;
1259         
1260         data.vc = *vc;
1261         data.rect = rect;
1262         data.select = select;
1263
1264         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1265         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1266 }
1267
1268 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1269 {
1270         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1271
1272         if (BLI_in_rcti(data->rect, x, y)) {
1273                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1274         }
1275 }
1276 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1277 {
1278         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1279
1280         data.vc= *vc;
1281         data.rect = rect;
1282         data.select = select;
1283
1284         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1285         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1286 }
1287
1288 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1289 {
1290         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1291
1292         if (BLI_in_rcti(data->rect, x, y)) {
1293                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1294         }
1295 }
1296 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1297 {
1298         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1299
1300         if(EM_check_backbuf(em_solidoffs+index)) {
1301                 if (data->pass==0) {
1302                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1303                                 EM_select_edge(eed, data->select);
1304                                 data->done = 1;
1305                         }
1306                 } else {
1307                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1308                                 EM_select_edge(eed, data->select);
1309                         }
1310                 }
1311         }
1312 }
1313 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1314 {
1315         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1316
1317         if (BLI_in_rcti(data->rect, x, y)) {
1318                 EM_select_face_fgon(data->vc.em, efa, data->select);
1319         }
1320 }
1321 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1322 {
1323         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1324         ToolSettings *ts= vc->scene->toolsettings;
1325         int bbsel;
1326         
1327         data.vc= *vc;
1328         data.rect = rect;
1329         data.select = select;
1330         data.pass = 0;
1331         data.done = 0;
1332
1333         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1334         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1335
1336         if(ts->selectmode & SCE_SELECT_VERTEX) {
1337                 if (bbsel) {
1338                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1339                 } else {
1340                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1341                 }
1342         }
1343         if(ts->selectmode & SCE_SELECT_EDGE) {
1344                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1345
1346                 data.pass = 0;
1347                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1348
1349                 if (data.done==0) {
1350                         data.pass = 1;
1351                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1352                 }
1353         }
1354         
1355         if(ts->selectmode & SCE_SELECT_FACE) {
1356                 if(bbsel) {
1357                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1358                 } else {
1359                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1360                 }
1361         }
1362         
1363         EM_free_backbuf();
1364                 
1365         EM_selectmode_flush(vc->em);
1366 }
1367
1368 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1369 {
1370         ViewContext vc;
1371         Scene *scene= CTX_data_scene(C);
1372         ScrArea *sa= CTX_wm_area(C);
1373         View3D *v3d= sa->spacedata.first;
1374         Object *obedit= CTX_data_edit_object(C);
1375         Object *obact= CTX_data_active_object(C);
1376         rcti rect;
1377         Base *base;
1378         MetaElem *ml;
1379         unsigned int buffer[4*MAXPICKBUF];
1380         int a, index;
1381         short hits, val;
1382
1383         view3d_operator_needs_opengl(C);
1384         
1385         /* setup view context for argument to callbacks */
1386         view3d_set_viewcontext(C, &vc);
1387         
1388         val= RNA_int_get(op->ptr, "event_type");
1389         rect.xmin= RNA_int_get(op->ptr, "xmin");
1390         rect.ymin= RNA_int_get(op->ptr, "ymin");
1391         rect.xmax= RNA_int_get(op->ptr, "xmax");
1392         rect.ymax= RNA_int_get(op->ptr, "ymax");
1393         
1394         if(obedit==NULL && (paint_facesel_test(OBACT))) {
1395 // XXX          face_borderselect();
1396                 return OPERATOR_FINISHED;
1397         }
1398         else if(obedit==NULL && (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
1399                 return PE_border_select(C, &rect, (val==LEFTMOUSE));
1400         }
1401         
1402         if(obedit) {
1403                 if(obedit->type==OB_MESH) {
1404                         Mesh *me= obedit->data;
1405                         vc.em= me->edit_mesh;
1406                         do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1407 //                      if (EM_texFaceCheck())
1408                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1409                         
1410                 }
1411                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1412                         do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1413                 }
1414                 else if(obedit->type==OB_MBALL) {
1415                         MetaBall *mb = (MetaBall*)obedit->data;
1416                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1417                         
1418                         ml= mb->editelems->first;
1419                         
1420                         while(ml) {
1421                                 for(a=0; a<hits; a++) {
1422                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1423                                                 ml->flag |= MB_SCALE_RAD;
1424                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1425                                                 else ml->flag &= ~SELECT;
1426                                                 break;
1427                                         }
1428                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1429                                                 ml->flag &= ~MB_SCALE_RAD;
1430                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1431                                                 else ml->flag &= ~SELECT;
1432                                                 break;
1433                                         }
1434                                 }
1435                                 ml= ml->next;
1436                         }
1437                 }
1438                 else if(obedit->type==OB_ARMATURE) {
1439                         bArmature *arm= obedit->data;
1440                         EditBone *ebone;
1441                         
1442                         /* clear flag we use to detect point was affected */
1443                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1444                                 ebone->flag &= ~BONE_DONE;
1445                         
1446                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1447                         
1448                         /* first we only check points inside the border */
1449                         for (a=0; a<hits; a++){
1450                                 index = buffer[(4*a)+3];
1451                                 if (index!=-1) {
1452                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1453                                         if (index & BONESEL_TIP) {
1454                                                 ebone->flag |= BONE_DONE;
1455                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1456                                                 else ebone->flag &= ~BONE_TIPSEL;
1457                                         }
1458                                         
1459                                         if (index & BONESEL_ROOT) {
1460                                                 ebone->flag |= BONE_DONE;
1461                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1462                                                 else ebone->flag &= ~BONE_ROOTSEL;
1463                                         }
1464                                 }
1465                         }
1466                         
1467                         /* now we have to flush tag from parents... */
1468                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1469                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1470                                         if(ebone->parent->flag & BONE_DONE)
1471                                                 ebone->flag |= BONE_DONE;
1472                                 }
1473                         }
1474                         
1475                         /* only select/deselect entire bones when no points where in the rect */
1476                         for (a=0; a<hits; a++){
1477                                 index = buffer[(4*a)+3];
1478                                 if (index!=-1) {
1479                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1480                                         if (index & BONESEL_BONE) {
1481                                                 if(!(ebone->flag & BONE_DONE)) {
1482                                                         if (val==LEFTMOUSE)
1483                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1484                                                         else
1485                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1486                                                 }
1487                                         }
1488                                 }
1489                         }
1490                         
1491                         ED_armature_sync_selection(arm->edbo);
1492                 }
1493                 else if(obedit->type==OB_LATTICE) {
1494                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1495                 }
1496         }
1497         else {  /* no editmode, unified for bones and objects */
1498                 Bone *bone;
1499                 Object *ob= OBACT;
1500                 unsigned int *vbuffer=NULL; /* selection buffer */
1501                 unsigned int *col;                      /* color in buffer      */
1502                 short selecting = 0;
1503                 int bone_only;
1504                 int totobj= MAXPICKBUF; // XXX solve later
1505                 
1506                 if((ob) && (ob->mode & OB_MODE_POSE))
1507                         bone_only= 1;
1508                 else
1509                         bone_only= 0;
1510                 
1511                 if (val==LEFTMOUSE)
1512                         selecting = 1;
1513                 
1514                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1515                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1516                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1517                 /*
1518                 LOGIC NOTES (theeth):
1519                 The buffer and ListBase have the same relative order, which makes the selection
1520                 very simple. Loop through both data sets at the same time, if the color
1521                 is the same as the object, we have a hit and can move to the next color
1522                 and object pair, if not, just move to the next object,
1523                 keeping the same color until we have a hit.
1524
1525                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1526                 does it incorrectly.
1527                 */
1528
1529                 if (hits>0) { /* no need to loop if there's no hit */
1530                         base= FIRSTBASE;
1531                         col = vbuffer + 3;
1532                         
1533                         while(base && hits) {
1534                                 Base *next = base->next;
1535                                 if(base->lay & v3d->lay) {
1536                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1537                                                 
1538                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1539                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1540                                                         if(bone) {
1541                                                                 if(selecting) {
1542                                                                         bone->flag |= BONE_SELECTED;
1543 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1544                                                                 }
1545                                                                 else {
1546                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1547 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1548                                                                 }
1549                                                         }
1550                                                 }
1551                                                 else if(!bone_only) {
1552                                                         if (selecting)
1553                                                                 ED_base_object_select(base, BA_SELECT);
1554                                                         else
1555                                                                 ED_base_object_select(base, BA_DESELECT);
1556                                                 }
1557
1558                                                 col+=4; /* next color */
1559                                                 hits--;
1560                                                 if(hits==0) break;
1561                                         }
1562                                 }
1563                                 
1564                                 base= next;
1565                         }
1566
1567                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1568
1569                 }
1570                 MEM_freeN(vbuffer);
1571         }
1572         return OPERATOR_FINISHED;
1573
1574
1575
1576 /* *****************Selection Operators******************* */
1577
1578 /* ****** Border Select ****** */
1579 void VIEW3D_OT_select_border(wmOperatorType *ot)
1580 {
1581         /* identifiers */
1582         ot->name= "Border Select";
1583         ot->description= "Select items using border selection.";
1584         ot->idname= "VIEW3D_OT_select_border";
1585         
1586         /* api callbacks */
1587         ot->invoke= WM_border_select_invoke;
1588         ot->exec= view3d_borderselect_exec;
1589         ot->modal= WM_border_select_modal;
1590         
1591         ot->poll= ED_operator_view3d_active;
1592         
1593         /* flags */
1594         ot->flag= OPTYPE_UNDO;
1595         
1596         /* rna */
1597         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1598         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1599         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1600         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1601         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1602
1603         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
1604 }
1605
1606 /* ****** Mouse Select ****** */
1607
1608
1609 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1610 {
1611         Object *obedit= CTX_data_edit_object(C);
1612         Object *obact= CTX_data_active_object(C);
1613         short extend= RNA_boolean_get(op->ptr, "extend");
1614         short center= RNA_boolean_get(op->ptr, "center");
1615         short enumerate= RNA_boolean_get(op->ptr, "enumerate");
1616
1617         view3d_operator_needs_opengl(C);
1618         
1619         if(obedit) {
1620                 if(obedit->type==OB_MESH)
1621                         mouse_mesh(C, event->mval, extend);
1622                 else if(obedit->type==OB_ARMATURE)
1623                         mouse_armature(C, event->mval, extend);
1624                 else if(obedit->type==OB_LATTICE)
1625                         mouse_lattice(C, event->mval, extend);
1626                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1627                         mouse_nurb(C, event->mval, extend);
1628                 else if(obedit->type==OB_MBALL)
1629                         mouse_mball(C, event->mval, extend);
1630                         
1631         }
1632         else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT)
1633                 PE_mouse_particles(C, event->mval, extend);
1634         else if(obact && paint_facesel_test(obact))
1635                 face_select(C, obact, event->mval, extend);
1636         else
1637                 mouse_select(C, event->mval, extend, center, enumerate);
1638
1639         /* allowing tweaks */
1640         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1641 }
1642
1643 void VIEW3D_OT_select(wmOperatorType *ot)
1644 {
1645         /* identifiers */
1646         ot->name= "Activate/Select";
1647         ot->description= "Activate/select item(s).";
1648         ot->idname= "VIEW3D_OT_select";
1649         
1650         /* api callbacks */
1651         ot->invoke= view3d_select_invoke;
1652         ot->poll= ED_operator_view3d_active;
1653         
1654         /* flags */
1655         ot->flag= OPTYPE_UNDO;
1656         
1657         /* properties */
1658         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
1659         RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting (object mode only).");
1660         RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only).");
1661 }
1662
1663
1664 /* -------------------- circle select --------------------------------------------- */
1665
1666 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1667 {
1668         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1669         int mx = x - data->mval[0], my = y - data->mval[1];
1670         float r = sqrt(mx*mx + my*my);
1671
1672         if (r<=data->radius) {
1673                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1674         }
1675 }
1676 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1677 {
1678         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1679
1680         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1681                 EM_select_edge(eed, data->select);
1682         }
1683 }
1684 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1685 {
1686         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1687         int mx = x - data->mval[0], my = y - data->mval[1];
1688         float r = sqrt(mx*mx + my*my);
1689         
1690         if (r<=data->radius) {
1691                 EM_select_face_fgon(data->vc->em, efa, data->select);
1692         }
1693 }
1694
1695 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1696 {
1697         ToolSettings *ts= vc->scene->toolsettings;
1698         int bbsel;
1699         Object *ob= vc->obact;
1700         
1701         if(vc->obedit==NULL && paint_facesel_test(ob)) {
1702                 Mesh *me = ob?ob->data:NULL;
1703
1704                 if (me) {
1705                         em_vertoffs= me->totface+1;     /* max index array */
1706
1707                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1708                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1709                         EM_free_backbuf();
1710
1711 // XXX                  object_tface_flags_changed(OBACT, 0);
1712                 }
1713         }
1714         else {
1715                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1716                 
1717                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1718                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1719
1720                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1721
1722                 data.select = selecting;
1723                 data.mval[0] = mval[0];
1724                 data.mval[1] = mval[1];
1725                 data.radius = rad;
1726
1727                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1728                         if(bbsel) {
1729                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1730                         } else {
1731                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1732                         }
1733                 }
1734
1735                 if(ts->selectmode & SCE_SELECT_EDGE) {
1736                         if (bbsel) {
1737                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1738                         } else {
1739                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1740                         }
1741                 }
1742                 
1743                 if(ts->selectmode & SCE_SELECT_FACE) {
1744                         if(bbsel) {
1745                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1746                         } else {
1747                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1748                         }
1749                 }
1750
1751                 EM_free_backbuf();
1752                 EM_selectmode_flush(vc->em);
1753         }
1754 }
1755
1756
1757 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1758 {
1759         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1760         int mx = x - data->mval[0], my = y - data->mval[1];
1761         float r = sqrt(mx*mx + my*my);
1762
1763         if (r<=data->radius) {
1764                 if (bp) {
1765                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1766                 } else {
1767                         if (beztindex==0) {
1768                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1769                         } else if (beztindex==1) {
1770                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1771                         } else {
1772                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1773                         }
1774                 }
1775         }
1776 }
1777 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1778 {
1779         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1780
1781         /* set vc-> edit data */
1782         
1783         data.select = selecting;
1784         data.mval[0] = mval[0];
1785         data.mval[1] = mval[1];
1786         data.radius = rad;
1787
1788         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1789         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1790 }
1791
1792
1793 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1794 {
1795         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1796         int mx = x - data->mval[0], my = y - data->mval[1];
1797         float r = sqrt(mx*mx + my*my);
1798
1799         if (r<=data->radius) {
1800                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1801         }
1802 }
1803 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1804 {
1805         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1806
1807         /* set vc-> edit data */
1808         
1809         data.select = selecting;
1810         data.mval[0] = mval[0];
1811         data.mval[1] = mval[1];
1812         data.radius = rad;
1813
1814         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1815         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1816 }
1817
1818 /** Callbacks for circle selection in Editmode */
1819
1820 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1821 {
1822         switch(vc->obedit->type) {              
1823         case OB_MESH:
1824                 mesh_circle_select(vc, selecting, mval, rad);
1825                 break;
1826         case OB_CURVE:
1827         case OB_SURF:
1828                 nurbscurve_circle_select(vc, selecting, mval, rad);
1829                 break;
1830         case OB_LATTICE:
1831                 lattice_circle_select(vc, selecting, mval, rad);
1832                 break;
1833         default:
1834                 return;
1835         }
1836 }
1837
1838 /* not a real operator, only for circle test */
1839 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1840 {
1841         ScrArea *sa= CTX_wm_area(C);
1842         ARegion *ar= CTX_wm_region(C);
1843         Scene *scene= CTX_data_scene(C);
1844         Object *obact= CTX_data_active_object(C);
1845         View3D *v3d= sa->spacedata.first;
1846         int x= RNA_int_get(op->ptr, "x");
1847         int y= RNA_int_get(op->ptr, "y");
1848         int radius= RNA_int_get(op->ptr, "radius");
1849         
1850         if(CTX_data_edit_object(C) || (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
1851                 ViewContext vc;
1852                 short mval[2], selecting;
1853                 
1854                 view3d_operator_needs_opengl(C);
1855                 
1856                 view3d_set_viewcontext(C, &vc);
1857                 mval[0]= x;
1858                 mval[1]= y;
1859                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1860
1861                 if(CTX_data_edit_object(C)) {
1862                         obedit_circle_select(&vc, selecting, mval, (float)radius);
1863                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
1864                 }
1865                 else
1866                         return PE_circle_select(C, selecting, mval, (float)radius);
1867         }
1868         else {
1869                 Base *base;
1870                 
1871                 for(base= FIRSTBASE; base; base= base->next) {
1872                         if(base->lay & v3d->lay) {
1873                                 project_short(ar, base->object->obmat[3], &base->sx);
1874                                 if(base->sx!=IS_CLIPPED) {
1875                                         int dx= base->sx-x;
1876                                         int dy= base->sy-y;
1877                                         if( dx*dx + dy*dy < radius*radius)
1878                                                 ED_base_object_select(base, BA_SELECT);
1879                                 }
1880                         }
1881                 }
1882                 
1883                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1884         }
1885         
1886         return OPERATOR_FINISHED;
1887 }
1888
1889 void VIEW3D_OT_select_circle(wmOperatorType *ot)
1890 {
1891         ot->name= "Circle Select";
1892         ot->description= "Select items using circle selection.";
1893         ot->idname= "VIEW3D_OT_select_circle";
1894         
1895         ot->invoke= WM_gesture_circle_invoke;
1896         ot->modal= WM_gesture_circle_modal;
1897         ot->exec= view3d_circle_select_exec;
1898         ot->poll= ED_operator_view3d_active;
1899         
1900         /* flags */
1901         ot->flag= OPTYPE_UNDO;
1902         
1903         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1904         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1905         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1906         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1907 }