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