rename PoseChannelConstraints to PoseBoneConstraints
[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(ViewContext *vc, Object *ob, bglMats *mats)
128 {
129         float cpy[4][4];
130         int i, j;
131
132         mul_m4_m4m4(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 /* 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 void 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         short hits;
1011         
1012         /* setup view context for argument to callbacks */
1013         view3d_set_viewcontext(C, &vc);
1014         
1015         /* always start list from basact in wire mode */
1016         startbase=  FIRSTBASE;
1017         if(BASACT && BASACT->next) startbase= BASACT->next;
1018         
1019         /* This block uses the control key to make the object selected by its center point rather then its contents */
1020         /* XXX later on, in editmode do not activate */
1021         if(vc.obedit==NULL && obcenter) {
1022                 
1023                 /* note; shift+alt goes to group-flush-selecting */
1024                 if(enumerate) {
1025                         basact= mouse_select_menu(C, &vc, NULL, 0, mval, extend);
1026                 } else {
1027                         base= startbase;
1028                         while(base) {
1029                                 if (BASE_SELECTABLE(v3d, base)) {
1030                                         project_short(ar, base->object->obmat[3], &base->sx);
1031                                         
1032                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1033                                         if(base==BASACT) temp+=10;
1034                                         if(temp<dist ) {
1035                                                 
1036                                                 dist= temp;
1037                                                 basact= base;
1038                                         }
1039                                 }
1040                                 base= base->next;
1041                                 
1042                                 if(base==0) base= FIRSTBASE;
1043                                 if(base==startbase) break;
1044                         }
1045                 }
1046         }
1047         else {
1048                 unsigned int buffer[4*MAXPICKBUF];
1049
1050                 /* if objects have posemode set, the bones are in the same selection buffer */
1051                 
1052                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1053                 
1054                 if(hits>0) {
1055                         int has_bones= 0;
1056                         
1057                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1058
1059                         /* note; shift+alt goes to group-flush-selecting */
1060                         if(has_bones==0 && enumerate) {
1061                                 basact= mouse_select_menu(C, &vc, buffer, hits, mval, extend);
1062                         } else {
1063                                 static short lastmval[2]={-100, -100};
1064                                 int donearest= 0;
1065                                 
1066                                 /* define if we use solid nearest select or not */
1067                                 if(v3d->drawtype>OB_WIRE) {
1068                                         donearest= 1;
1069                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1070                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1071                                                         donearest= 0;
1072                                         }
1073                                 }
1074                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1075                                 
1076                                 if(donearest) {
1077                                         unsigned int min= 0xFFFFFFFF;
1078                                         int selcol= 0, notcol=0;
1079                                         
1080
1081                                         if(has_bones) {
1082                                                 /* we skip non-bone hits */
1083                                                 for(a=0; a<hits; a++) {
1084                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1085                                                                 min= buffer[4*a+1];
1086                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1087                                                         }
1088                                                 }
1089                                         }
1090                                         else {
1091                                                 /* only exclude active object when it is selected... */
1092                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1093                                         
1094                                                 for(a=0; a<hits; a++) {
1095                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1096                                                                 min= buffer[4*a+1];
1097                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1098                                                         }
1099                                                 }
1100                                         }
1101
1102                                         base= FIRSTBASE;
1103                                         while(base) {
1104                                                 if(base->lay & v3d->lay) {
1105                                                         if(base->selcol==selcol) break;
1106                                                 }
1107                                                 base= base->next;
1108                                         }
1109                                         if(base) basact= base;
1110                                 }
1111                                 else {
1112                                         
1113                                         base= startbase;
1114                                         while(base) {
1115                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1116                                                  * with an un-selectable choice */
1117                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1118                                                         base=base->next;
1119                                                         if(base==NULL) base= FIRSTBASE;
1120                                                         if(base==startbase) break;
1121                                                 }
1122                                         
1123                                                 if(base->lay & v3d->lay) {
1124                                                         for(a=0; a<hits; a++) {
1125                                                                 if(has_bones) {
1126                                                                         /* skip non-bone objects */
1127                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1128                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1129                                                                                         basact= base;
1130                                                                         }
1131                                                                 }
1132                                                                 else {
1133                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1134                                                                                 basact= base;
1135                                                                 }
1136                                                         }
1137                                                 }
1138                                                 
1139                                                 if(basact) break;
1140                                                 
1141                                                 base= base->next;
1142                                                 if(base==NULL) base= FIRSTBASE;
1143                                                 if(base==startbase) break;
1144                                         }
1145                                 }
1146                         }
1147                         
1148                         if(has_bones && basact) {
1149                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1150                                 
1151                                         /* we make the armature selected: 
1152                                            not-selected active object in posemode won't work well for tools */
1153                                         basact->flag|= SELECT;
1154                                         basact->object->flag= basact->flag;
1155                                         
1156                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1157                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1158                                         
1159                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1160                                         if(BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) {
1161                                                 /* prevent activating */
1162                                                 basact= NULL;
1163                                         }
1164
1165                                 }
1166                                 /* prevent bone selecting to pass on to object selecting */
1167                                 if(basact==BASACT)
1168                                         basact= NULL;
1169                         }
1170                 }
1171         }
1172         
1173         /* so, do we have something selected? */
1174         if(basact) {
1175                 
1176                 if(vc.obedit) {
1177                         /* only do select */
1178                         deselectall_except(scene, basact);
1179                         ED_base_object_select(basact, BA_SELECT);
1180                 }
1181                 /* also prevent making it active on mouse selection */
1182                 else if (BASE_SELECTABLE(v3d, basact)) {
1183
1184                         oldbasact= BASACT;
1185                         
1186                         if(!extend) {
1187                                 deselectall_except(scene, basact);
1188                                 ED_base_object_select(basact, BA_SELECT);
1189                         }
1190                         else if(0) {
1191                                 // XXX select_all_from_groups(basact);
1192                         }
1193                         else {
1194                                 if(basact->flag & SELECT) {
1195                                         if(basact==oldbasact)
1196                                                 ED_base_object_select(basact, BA_DESELECT);
1197                                 }
1198                                 else ED_base_object_select(basact, BA_SELECT);
1199                         }
1200
1201                         if(oldbasact != basact) {
1202                                 ED_base_object_activate(C, basact); /* adds notifier */
1203                         }
1204
1205                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1206                 }
1207         }
1208 }
1209
1210 /* ********************  border and circle ************************************** */
1211
1212
1213 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1214 {
1215         int radsq= rad*rad;
1216         float v1[2], v2[2], v3[2];
1217         
1218         /* check points in circle itself */
1219         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1220         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1221         
1222         /* pointdistline */
1223         v3[0]= centx;
1224         v3[1]= centy;
1225         v1[0]= x1;
1226         v1[1]= y1;
1227         v2[0]= x2;
1228         v2[1]= y2;
1229         
1230         if( dist_to_line_segment_v2(v3, v1, v2) < (float)rad ) return 1;
1231         
1232         return 0;
1233 }
1234
1235 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1236 {
1237         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1238
1239         if (BLI_in_rcti(data->rect, x, y)) {
1240                 if (bp) {
1241                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1242                 } else {
1243                         Curve *cu= data->vc.obedit->data;
1244                         
1245                         if (cu->drawflag & CU_HIDE_HANDLES) {
1246                                 /* can only be beztindex==0 here since handles are hidden */
1247                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1248                         } else {
1249                                 if (beztindex==0) {
1250                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1251                                 } else if (beztindex==1) {
1252                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1253                                 } else {
1254                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1255                                 }
1256                         }
1257                 }
1258         }
1259 }
1260 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1261 {
1262         struct { ViewContext vc; rcti *rect; int select; } data;
1263         
1264         data.vc = *vc;
1265         data.rect = rect;
1266         data.select = select;
1267
1268         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1269         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1270 }
1271
1272 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1273 {
1274         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1275
1276         if (BLI_in_rcti(data->rect, x, y)) {
1277                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1278         }
1279 }
1280 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1281 {
1282         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1283
1284         data.vc= *vc;
1285         data.rect = rect;
1286         data.select = select;
1287
1288         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1289         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1290 }
1291
1292 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1293 {
1294         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1295
1296         if (BLI_in_rcti(data->rect, x, y)) {
1297                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1298         }
1299 }
1300 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1301 {
1302         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1303
1304         if(EM_check_backbuf(em_solidoffs+index)) {
1305                 if (data->pass==0) {
1306                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1307                                 EM_select_edge(eed, data->select);
1308                                 data->done = 1;
1309                         }
1310                 } else {
1311                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1312                                 EM_select_edge(eed, data->select);
1313                         }
1314                 }
1315         }
1316 }
1317 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1318 {
1319         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1320
1321         if (BLI_in_rcti(data->rect, x, y)) {
1322                 EM_select_face_fgon(data->vc.em, efa, data->select);
1323         }
1324 }
1325 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1326 {
1327         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1328         ToolSettings *ts= vc->scene->toolsettings;
1329         int bbsel;
1330         
1331         data.vc= *vc;
1332         data.rect = rect;
1333         data.select = select;
1334         data.pass = 0;
1335         data.done = 0;
1336
1337         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1338         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1339
1340         if(ts->selectmode & SCE_SELECT_VERTEX) {
1341                 if (bbsel) {
1342                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1343                 } else {
1344                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1345                 }
1346         }
1347         if(ts->selectmode & SCE_SELECT_EDGE) {
1348                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1349
1350                 data.pass = 0;
1351                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1352
1353                 if (data.done==0) {
1354                         data.pass = 1;
1355                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1356                 }
1357         }
1358         
1359         if(ts->selectmode & SCE_SELECT_FACE) {
1360                 if(bbsel) {
1361                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1362                 } else {
1363                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1364                 }
1365         }
1366         
1367         EM_free_backbuf();
1368                 
1369         EM_selectmode_flush(vc->em);
1370 }
1371
1372 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1373 {
1374         ViewContext vc;
1375         Scene *scene= CTX_data_scene(C);
1376         ScrArea *sa= CTX_wm_area(C);
1377         View3D *v3d= sa->spacedata.first;
1378         Object *obedit= CTX_data_edit_object(C);
1379         Object *obact= CTX_data_active_object(C);
1380         rcti rect;
1381         Base *base;
1382         MetaElem *ml;
1383         unsigned int buffer[4*MAXPICKBUF];
1384         int a, index;
1385         short hits, selecting;
1386
1387         view3d_operator_needs_opengl(C);
1388         
1389         /* setup view context for argument to callbacks */
1390         view3d_set_viewcontext(C, &vc);
1391         
1392         selecting= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
1393         rect.xmin= RNA_int_get(op->ptr, "xmin");
1394         rect.ymin= RNA_int_get(op->ptr, "ymin");
1395         rect.xmax= RNA_int_get(op->ptr, "xmax");
1396         rect.ymax= RNA_int_get(op->ptr, "ymax");
1397         
1398         if(obedit==NULL && (paint_facesel_test(OBACT))) {
1399                 face_borderselect(C, obact, &rect, selecting);
1400                 return OPERATOR_FINISHED;
1401         }
1402         else if(obedit==NULL && (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
1403                 return PE_border_select(C, &rect, selecting);
1404         }
1405         
1406         if(obedit) {
1407                 if(obedit->type==OB_MESH) {
1408                         Mesh *me= obedit->data;
1409                         vc.em= me->edit_mesh;
1410                         do_mesh_box_select(&vc, &rect, selecting);
1411 //                      if (EM_texFaceCheck())
1412                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1413                         
1414                 }
1415                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1416                         do_nurbs_box_select(&vc, &rect, selecting);
1417                 }
1418                 else if(obedit->type==OB_MBALL) {
1419                         MetaBall *mb = (MetaBall*)obedit->data;
1420                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1421                         
1422                         ml= mb->editelems->first;
1423                         
1424                         while(ml) {
1425                                 for(a=0; a<hits; a++) {
1426                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1427                                                 ml->flag |= MB_SCALE_RAD;
1428                                                 if(selecting)   ml->flag |= SELECT;
1429                                                 else                    ml->flag &= ~SELECT;
1430                                                 break;
1431                                         }
1432                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1433                                                 ml->flag &= ~MB_SCALE_RAD;
1434                                                 if(selecting)   ml->flag |= SELECT;
1435                                                 else                    ml->flag &= ~SELECT;
1436                                                 break;
1437                                         }
1438                                 }
1439                                 ml= ml->next;
1440                         }
1441                 }
1442                 else if(obedit->type==OB_ARMATURE) {
1443                         bArmature *arm= obedit->data;
1444                         EditBone *ebone;
1445                         
1446                         /* clear flag we use to detect point was affected */
1447                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1448                                 ebone->flag &= ~BONE_DONE;
1449                         
1450                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1451                         
1452                         /* first we only check points inside the border */
1453                         for (a=0; a<hits; a++){
1454                                 index = buffer[(4*a)+3];
1455                                 if (index!=-1) {
1456                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1457                                         if (index & BONESEL_TIP) {
1458                                                 ebone->flag |= BONE_DONE;
1459                                                 if (selecting)  ebone->flag |= BONE_TIPSEL;
1460                                                 else                    ebone->flag &= ~BONE_TIPSEL;
1461                                         }
1462                                         
1463                                         if (index & BONESEL_ROOT) {
1464                                                 ebone->flag |= BONE_DONE;
1465                                                 if (selecting)  ebone->flag |= BONE_ROOTSEL;
1466                                                 else                    ebone->flag &= ~BONE_ROOTSEL;
1467                                         }
1468                                 }
1469                         }
1470                         
1471                         /* now we have to flush tag from parents... */
1472                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1473                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1474                                         if(ebone->parent->flag & BONE_DONE)
1475                                                 ebone->flag |= BONE_DONE;
1476                                 }
1477                         }
1478                         
1479                         /* only select/deselect entire bones when no points where in the rect */
1480                         for (a=0; a<hits; a++){
1481                                 index = buffer[(4*a)+3];
1482                                 if (index!=-1) {
1483                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1484                                         if (index & BONESEL_BONE) {
1485                                                 if(!(ebone->flag & BONE_DONE)) {
1486                                                         if (selecting)
1487                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1488                                                         else
1489                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1490                                                 }
1491                                         }
1492                                 }
1493                         }
1494                         
1495                         ED_armature_sync_selection(arm->edbo);
1496                 }
1497                 else if(obedit->type==OB_LATTICE) {
1498                         do_lattice_box_select(&vc, &rect, selecting);
1499                 }
1500         }
1501         else {  /* no editmode, unified for bones and objects */
1502                 Bone *bone;
1503                 Object *ob= OBACT;
1504                 unsigned int *vbuffer=NULL; /* selection buffer */
1505                 unsigned int *col;                      /* color in buffer      */
1506                 int bone_only;
1507                 int totobj= MAXPICKBUF; // XXX solve later
1508                 
1509                 if((ob) && (ob->mode & OB_MODE_POSE))
1510                         bone_only= 1;
1511                 else
1512                         bone_only= 0;
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                                                                         bArmature *arm= base->object->data;
1547                                                                         bone->flag &= ~BONE_SELECTED;
1548 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1549                                                                         if(arm->act_bone==bone)
1550                                                                                 arm->act_bone= NULL;
1551                                                                         
1552                                                                 }
1553                                                         }
1554                                                 }
1555                                                 else if(!bone_only) {
1556                                                         if (selecting)
1557                                                                 ED_base_object_select(base, BA_SELECT);
1558                                                         else
1559                                                                 ED_base_object_select(base, BA_DESELECT);
1560                                                 }
1561
1562                                                 col+=4; /* next color */
1563                                                 hits--;
1564                                                 if(hits==0) break;
1565                                         }
1566                                 }
1567                                 
1568                                 base= next;
1569                         }
1570
1571                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1572
1573                 }
1574                 MEM_freeN(vbuffer);
1575         }
1576         return OPERATOR_FINISHED;
1577
1578
1579
1580 /* *****************Selection Operators******************* */
1581
1582 /* ****** Border Select ****** */
1583 void VIEW3D_OT_select_border(wmOperatorType *ot)
1584 {
1585         /* identifiers */
1586         ot->name= "Border Select";
1587         ot->description= "Select items using border selection.";
1588         ot->idname= "VIEW3D_OT_select_border";
1589         
1590         /* api callbacks */
1591         ot->invoke= WM_border_select_invoke;
1592         ot->exec= view3d_borderselect_exec;
1593         ot->modal= WM_border_select_modal;
1594         
1595         ot->poll= ED_operator_view3d_active;
1596         
1597         /* flags */
1598         ot->flag= OPTYPE_UNDO;
1599         
1600         /* rna */
1601         WM_operator_properties_gesture_border(ot, TRUE);
1602 }
1603
1604 /* ****** Mouse Select ****** */
1605
1606
1607 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1608 {
1609         Object *obedit= CTX_data_edit_object(C);
1610         Object *obact= CTX_data_active_object(C);
1611         short extend= RNA_boolean_get(op->ptr, "extend");
1612         short center= RNA_boolean_get(op->ptr, "center");
1613         short enumerate= RNA_boolean_get(op->ptr, "enumerate");
1614
1615         view3d_operator_needs_opengl(C);
1616         
1617         if(obedit) {
1618                 if(obedit->type==OB_MESH)
1619                         mouse_mesh(C, event->mval, extend);
1620                 else if(obedit->type==OB_ARMATURE)
1621                         mouse_armature(C, event->mval, extend);
1622                 else if(obedit->type==OB_LATTICE)
1623                         mouse_lattice(C, event->mval, extend);
1624                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1625                         mouse_nurb(C, event->mval, extend);
1626                 else if(obedit->type==OB_MBALL)
1627                         mouse_mball(C, event->mval, extend);
1628                         
1629         }
1630         else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT)
1631                 PE_mouse_particles(C, event->mval, extend);
1632         else if(obact && paint_facesel_test(obact))
1633                 face_select(C, obact, event->mval, extend);
1634         else
1635                 mouse_select(C, event->mval, extend, center, enumerate);
1636
1637         /* allowing tweaks */
1638         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1639 }
1640
1641 void VIEW3D_OT_select(wmOperatorType *ot)
1642 {
1643         /* identifiers */
1644         ot->name= "Activate/Select";
1645         ot->description= "Activate/select item(s).";
1646         ot->idname= "VIEW3D_OT_select";
1647         
1648         /* api callbacks */
1649         ot->invoke= view3d_select_invoke;
1650         ot->poll= ED_operator_view3d_active;
1651         
1652         /* flags */
1653         ot->flag= OPTYPE_UNDO;
1654         
1655         /* properties */
1656         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
1657         RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting (object mode only).");
1658         RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only).");
1659 }
1660
1661
1662 /* -------------------- circle select --------------------------------------------- */
1663
1664 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1665 {
1666         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1667         int mx = x - data->mval[0], my = y - data->mval[1];
1668         float r = sqrt(mx*mx + my*my);
1669
1670         if (r<=data->radius) {
1671                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1672         }
1673 }
1674 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1675 {
1676         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1677
1678         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1679                 EM_select_edge(eed, data->select);
1680         }
1681 }
1682 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1683 {
1684         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1685         int mx = x - data->mval[0], my = y - data->mval[1];
1686         float r = sqrt(mx*mx + my*my);
1687         
1688         if (r<=data->radius) {
1689                 EM_select_face_fgon(data->vc->em, efa, data->select);
1690         }
1691 }
1692
1693 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1694 {
1695         ToolSettings *ts= vc->scene->toolsettings;
1696         int bbsel;
1697         Object *ob= vc->obact;
1698         
1699         if(vc->obedit==NULL && paint_facesel_test(ob)) {
1700                 Mesh *me = ob?ob->data:NULL;
1701
1702                 if (me) {
1703                         em_vertoffs= me->totface+1;     /* max index array */
1704
1705                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1706                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1707                         EM_free_backbuf();
1708
1709 // XXX                  object_tface_flags_changed(OBACT, 0);
1710                 }
1711         }
1712         else {
1713                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1714                 
1715                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1716                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1717
1718                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1719
1720                 data.vc = vc;
1721                 data.select = selecting;
1722                 data.mval[0] = mval[0];
1723                 data.mval[1] = mval[1];
1724                 data.radius = rad;
1725
1726                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1727                         if(bbsel) {
1728                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1729                         } else {
1730                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1731                         }
1732                 }
1733
1734                 if(ts->selectmode & SCE_SELECT_EDGE) {
1735                         if (bbsel) {
1736                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1737                         } else {
1738                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1739                         }
1740                 }
1741                 
1742                 if(ts->selectmode & SCE_SELECT_FACE) {
1743                         if(bbsel) {
1744                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1745                         } else {
1746                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1747                         }
1748                 }
1749
1750                 EM_free_backbuf();
1751                 EM_selectmode_flush(vc->em);
1752         }
1753 }
1754
1755
1756 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1757 {
1758         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1759         int mx = x - data->mval[0], my = y - data->mval[1];
1760         float r = sqrt(mx*mx + my*my);
1761
1762         if (r<=data->radius) {
1763                 if (bp) {
1764                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1765                 } else {
1766                         if (beztindex==0) {
1767                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1768                         } else if (beztindex==1) {
1769                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1770                         } else {
1771                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1772                         }
1773                 }
1774         }
1775 }
1776 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1777 {
1778         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1779
1780         /* set vc-> edit data */
1781         
1782         data.select = selecting;
1783         data.mval[0] = mval[0];
1784         data.mval[1] = mval[1];
1785         data.radius = rad;
1786
1787         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1788         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1789 }
1790
1791
1792 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1793 {
1794         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1795         int mx = x - data->mval[0], my = y - data->mval[1];
1796         float r = sqrt(mx*mx + my*my);
1797
1798         if (r<=data->radius) {
1799                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1800         }
1801 }
1802 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1803 {
1804         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1805
1806         /* set vc-> edit data */
1807         
1808         data.select = selecting;
1809         data.mval[0] = mval[0];
1810         data.mval[1] = mval[1];
1811         data.radius = rad;
1812
1813         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1814         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1815 }
1816
1817
1818 static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head)
1819 {
1820         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1821         int mx = x - data->mval[0], my = y - data->mval[1];
1822         float r = sqrt(mx*mx + my*my);
1823         
1824         if (r <= data->radius) {
1825                 if (head) {
1826                         if (data->select)
1827                                 ebone->flag |= BONE_ROOTSEL;
1828                         else 
1829                                 ebone->flag &= ~BONE_ROOTSEL;
1830                 }
1831                 else {
1832                         if (data->select)
1833                                 ebone->flag |= BONE_TIPSEL;
1834                         else 
1835                                 ebone->flag &= ~BONE_TIPSEL;
1836                 }
1837                 return 1;
1838         }
1839         return 0;
1840 }
1841 static void armature_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1842 {
1843         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1844         bArmature *arm= vc->obedit->data;
1845         EditBone *ebone;
1846         
1847         /* set vc->edit data */
1848         data.select = selecting;
1849         data.mval[0] = mval[0];
1850         data.mval[1] = mval[1];
1851         data.radius = rad;
1852
1853         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1854         
1855         /* check each EditBone... */
1856         // TODO: could be optimised at some point
1857         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
1858                 short sco1[2], sco2[2], didpoint=0;
1859                 float vec[3];
1860                 
1861                 /* project head location to screenspace */
1862                 VECCOPY(vec, ebone->head);
1863                 mul_m4_v3(vc->obedit->obmat, vec);
1864                 project_short(vc->ar, vec, sco1);
1865                 
1866                 /* project tail location to screenspace */
1867                 VECCOPY(vec, ebone->tail);
1868                 mul_m4_v3(vc->obedit->obmat, vec);
1869                 project_short(vc->ar, vec, sco2);
1870                 
1871                 /* check if the head and/or tail is in the circle 
1872                  *      - the call to check also does the selection already
1873                  */
1874                 if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1))
1875                         didpoint= 1;
1876                 if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0))
1877                         didpoint= 1;
1878                         
1879                 /* only if the endpoints didn't get selected, deal with the middle of the bone too */
1880                 // XXX should we just do this always?
1881                 if ( (didpoint==0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1]) ) {
1882                         if (selecting) 
1883                                 ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
1884                         else 
1885                                 ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
1886                 }
1887         }
1888
1889         ED_armature_validate_active(arm);
1890 }
1891
1892 /** Callbacks for circle selection in Editmode */
1893
1894 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1895 {
1896         switch(vc->obedit->type) {              
1897         case OB_MESH:
1898                 mesh_circle_select(vc, selecting, mval, rad);
1899                 break;
1900         case OB_CURVE:
1901         case OB_SURF:
1902                 nurbscurve_circle_select(vc, selecting, mval, rad);
1903                 break;
1904         case OB_LATTICE:
1905                 lattice_circle_select(vc, selecting, mval, rad);
1906                 break;
1907         case OB_ARMATURE:
1908                 armature_circle_select(vc, selecting, mval, rad);
1909                 break;
1910         default:
1911                 return;
1912         }
1913 }
1914
1915 /* not a real operator, only for circle test */
1916 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1917 {
1918         ScrArea *sa= CTX_wm_area(C);
1919         ARegion *ar= CTX_wm_region(C);
1920         Scene *scene= CTX_data_scene(C);
1921         Object *obact= CTX_data_active_object(C);
1922         View3D *v3d= sa->spacedata.first;
1923         int x= RNA_int_get(op->ptr, "x");
1924         int y= RNA_int_get(op->ptr, "y");
1925         int radius= RNA_int_get(op->ptr, "radius");
1926     int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1927     int selecting;
1928         
1929     selecting= (gesture_mode==GESTURE_MODAL_SELECT);
1930     
1931         if(CTX_data_edit_object(C) || (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
1932                 ViewContext vc;
1933                 short mval[2];
1934                 
1935                 view3d_operator_needs_opengl(C);
1936                 
1937                 view3d_set_viewcontext(C, &vc);
1938                 mval[0]= x;
1939                 mval[1]= y;
1940
1941                 if(CTX_data_edit_object(C)) {
1942                         obedit_circle_select(&vc, selecting, mval, (float)radius);
1943                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
1944                 }
1945                 else
1946                         return PE_circle_select(C, selecting, mval, (float)radius);
1947         }
1948         else {
1949                 Base *base;
1950                 selecting= selecting?BA_SELECT:BA_DESELECT;
1951                 for(base= FIRSTBASE; base; base= base->next) {
1952                         if(base->lay & v3d->lay) {
1953                                 project_short(ar, base->object->obmat[3], &base->sx);
1954                                 if(base->sx!=IS_CLIPPED) {
1955                                         int dx= base->sx-x;
1956                                         int dy= base->sy-y;
1957                                         if( dx*dx + dy*dy < radius*radius)
1958                                                 ED_base_object_select(base, selecting);
1959                                 }
1960                         }
1961                 }
1962                 
1963                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1964         }
1965         
1966         return OPERATOR_FINISHED;
1967 }
1968
1969 void VIEW3D_OT_select_circle(wmOperatorType *ot)
1970 {
1971         ot->name= "Circle Select";
1972         ot->description= "Select items using circle selection.";
1973         ot->idname= "VIEW3D_OT_select_circle";
1974         
1975         ot->invoke= WM_gesture_circle_invoke;
1976         ot->modal= WM_gesture_circle_modal;
1977         ot->exec= view3d_circle_select_exec;
1978         ot->poll= ED_operator_view3d_active;
1979         
1980         /* flags */
1981         ot->flag= OPTYPE_UNDO;
1982         
1983         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1984         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1985         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1986         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1987 }