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