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