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