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