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