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