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