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