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