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