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