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