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