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