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