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