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